From 01e6a12c046987668bd06d0e3c7e65f0ed090fe3 Mon Sep 17 00:00:00 2001 From: Benjamin Kott Date: Mon, 2 Dec 2024 12:12:00 +0100 Subject: [PATCH 1/3] [BUGFIX] Correct API Responses (#474) --- composer.json | 3 + composer.lock | 319 +++++++++--------- config/packages/framework.yaml | 5 + config/services.yaml | 5 + src/Entity/MajorVersion.php | 15 +- src/Entity/Release.php | 11 +- tests/Functional/Controller/Api/ApiCase.php | 95 ++++++ .../MajorVersion/ReleaseControllerTest.php | 194 +++++++++++ .../RequirementsControllerTest.php | 32 ++ .../Api/MajorVersionControllerTest.php | 89 +++++ .../Controller/Api/ReleaseControllerTest.php | 112 ++++++ tests/Unit/phpunit.xml | 4 + 12 files changed, 714 insertions(+), 170 deletions(-) create mode 100644 tests/Functional/Controller/Api/MajorVersion/ReleaseControllerTest.php diff --git a/composer.json b/composer.json index c23fdd80..0c842208 100644 --- a/composer.json +++ b/composer.json @@ -158,6 +158,9 @@ "sort-packages": true }, "extra": { + "runtime": { + "use_putenv": true + }, "bamarni-bin": { "bin-links": true, "forward-command": false, diff --git a/composer.lock b/composer.lock index 5536fbbf..3f23f484 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "855af168d93bcddedac006053c3f9361", + "content-hash": "72eee83f03b66b5fe93714e570e4293c", "packages": [ { "name": "composer/ca-bundle", - "version": "1.5.3", + "version": "1.5.4", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "3b1fc3f0be055baa7c6258b1467849c3e8204eb2" + "reference": "bc0593537a463e55cadf45fd938d23b75095b7e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/3b1fc3f0be055baa7c6258b1467849c3e8204eb2", - "reference": "3b1fc3f0be055baa7c6258b1467849c3e8204eb2", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/bc0593537a463e55cadf45fd938d23b75095b7e1", + "reference": "bc0593537a463e55cadf45fd938d23b75095b7e1", "shasum": "" }, "require": { @@ -64,7 +64,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.5.3" + "source": "https://github.com/composer/ca-bundle/tree/1.5.4" }, "funding": [ { @@ -80,7 +80,7 @@ "type": "tidelift" } ], - "time": "2024-11-04T10:15:26+00:00" + "time": "2024-11-27T15:35:25+00:00" }, { "name": "composer/semver", @@ -1560,16 +1560,16 @@ }, { "name": "easycorp/easyadmin-bundle", - "version": "v4.16.1", + "version": "v4.18.0", "source": { "type": "git", "url": "https://github.com/EasyCorp/EasyAdminBundle.git", - "reference": "e9e90f8659f9f8b508b46fe8d380ba28f6b6e498" + "reference": "c1b694c1890d6f20858802d201cd7199212dc42a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/EasyCorp/EasyAdminBundle/zipball/e9e90f8659f9f8b508b46fe8d380ba28f6b6e498", - "reference": "e9e90f8659f9f8b508b46fe8d380ba28f6b6e498", + "url": "https://api.github.com/repos/EasyCorp/EasyAdminBundle/zipball/c1b694c1890d6f20858802d201cd7199212dc42a", + "reference": "c1b694c1890d6f20858802d201cd7199212dc42a", "shasum": "" }, "require": { @@ -1644,7 +1644,7 @@ ], "support": { "issues": "https://github.com/EasyCorp/EasyAdminBundle/issues", - "source": "https://github.com/EasyCorp/EasyAdminBundle/tree/v4.16.1" + "source": "https://github.com/EasyCorp/EasyAdminBundle/tree/v4.18.0" }, "funding": [ { @@ -1652,7 +1652,7 @@ "type": "github" } ], - "time": "2024-11-25T18:58:01+00:00" + "time": "2024-11-28T19:54:15+00:00" }, { "name": "egulias/email-validator", @@ -3764,16 +3764,16 @@ }, { "name": "symfony/cache", - "version": "v6.4.14", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "36fb8aa88833708e9f29014b6f15fac051a8b613" + "reference": "70d60e9a3603108563010f8592dff15a6f15dfae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/36fb8aa88833708e9f29014b6f15fac051a8b613", - "reference": "36fb8aa88833708e9f29014b6f15fac051a8b613", + "url": "https://api.github.com/repos/symfony/cache/zipball/70d60e9a3603108563010f8592dff15a6f15dfae", + "reference": "70d60e9a3603108563010f8592dff15a6f15dfae", "shasum": "" }, "require": { @@ -3840,7 +3840,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v6.4.14" + "source": "https://github.com/symfony/cache/tree/v6.4.16" }, "funding": [ { @@ -3856,20 +3856,20 @@ "type": "tidelift" } ], - "time": "2024-11-05T15:34:40+00:00" + "time": "2024-11-20T10:10:54+00:00" }, { "name": "symfony/cache-contracts", - "version": "v2.5.3", + "version": "v2.5.4", "source": { "type": "git", "url": "https://github.com/symfony/cache-contracts.git", - "reference": "fee6db04d913094e2fb55ff8e7db5685a8134463" + "reference": "517c3a3619dadfa6952c4651767fcadffb4df65e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/fee6db04d913094e2fb55ff8e7db5685a8134463", - "reference": "fee6db04d913094e2fb55ff8e7db5685a8134463", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/517c3a3619dadfa6952c4651767fcadffb4df65e", + "reference": "517c3a3619dadfa6952c4651767fcadffb4df65e", "shasum": "" }, "require": { @@ -3919,7 +3919,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/cache-contracts/tree/v2.5.3" + "source": "https://github.com/symfony/cache-contracts/tree/v2.5.4" }, "funding": [ { @@ -3935,7 +3935,7 @@ "type": "tidelift" } ], - "time": "2024-01-23T13:51:25+00:00" + "time": "2024-09-25T14:11:13+00:00" }, { "name": "symfony/clock", @@ -4182,16 +4182,16 @@ }, { "name": "symfony/dependency-injection", - "version": "v6.4.15", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "70ab1f65a4516ef741e519ea938e6aa465e6aa36" + "reference": "7a379d8871f6a36f01559c14e11141cc02eb8dc8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/70ab1f65a4516ef741e519ea938e6aa465e6aa36", - "reference": "70ab1f65a4516ef741e519ea938e6aa465e6aa36", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/7a379d8871f6a36f01559c14e11141cc02eb8dc8", + "reference": "7a379d8871f6a36f01559c14e11141cc02eb8dc8", "shasum": "" }, "require": { @@ -4243,7 +4243,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v6.4.15" + "source": "https://github.com/symfony/dependency-injection/tree/v6.4.16" }, "funding": [ { @@ -4259,20 +4259,20 @@ "type": "tidelift" } ], - "time": "2024-11-09T06:56:25+00:00" + "time": "2024-11-25T14:52:46+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.5.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", "shasum": "" }, "require": { @@ -4310,7 +4310,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" }, "funding": [ { @@ -4326,7 +4326,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/doctrine-bridge", @@ -4440,16 +4440,16 @@ }, { "name": "symfony/dotenv", - "version": "v6.4.13", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "436ae2dd89360fea8c7d5ff3f48ecf523c80bfb4" + "reference": "1ac5e7e7e862d4d574258daf08bd569ba926e4a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/436ae2dd89360fea8c7d5ff3f48ecf523c80bfb4", - "reference": "436ae2dd89360fea8c7d5ff3f48ecf523c80bfb4", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/1ac5e7e7e862d4d574258daf08bd569ba926e4a5", + "reference": "1ac5e7e7e862d4d574258daf08bd569ba926e4a5", "shasum": "" }, "require": { @@ -4494,7 +4494,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v6.4.13" + "source": "https://github.com/symfony/dotenv/tree/v6.4.16" }, "funding": [ { @@ -4510,7 +4510,7 @@ "type": "tidelift" } ], - "time": "2024-09-28T07:43:51+00:00" + "time": "2024-11-27T11:08:19+00:00" }, { "name": "symfony/error-handler", @@ -4669,16 +4669,16 @@ }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.5.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50" + "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/8f93aec25d41b72493c6ddff14e916177c9efc50", - "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7642f5e970b672283b7823222ae8ef8bbc160b9f", + "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f", "shasum": "" }, "require": { @@ -4725,7 +4725,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.1" }, "funding": [ { @@ -4741,7 +4741,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/expression-language", @@ -5253,23 +5253,23 @@ }, { "name": "symfony/http-client", - "version": "v6.4.15", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "cb4073c905cd12b8496d24ac428a9228c1750670" + "reference": "60a113666fa67e598abace38e5f46a0954d8833d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/cb4073c905cd12b8496d24ac428a9228c1750670", - "reference": "cb4073c905cd12b8496d24ac428a9228c1750670", + "url": "https://api.github.com/repos/symfony/http-client/zipball/60a113666fa67e598abace38e5f46a0954d8833d", + "reference": "60a113666fa67e598abace38e5f46a0954d8833d", "shasum": "" }, "require": { "php": ">=8.1", "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-client-contracts": "^3.4.1", + "symfony/http-client-contracts": "~3.4.3|^3.5.1", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -5326,7 +5326,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.4.15" + "source": "https://github.com/symfony/http-client/tree/v6.4.16" }, "funding": [ { @@ -5342,20 +5342,20 @@ "type": "tidelift" } ], - "time": "2024-11-13T13:40:18+00:00" + "time": "2024-11-27T11:52:33+00:00" }, { "name": "symfony/http-client-contracts", - "version": "v3.5.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "20414d96f391677bf80078aa55baece78b82647d" + "reference": "c2f3ad828596624ca39ea40f83617ef51ca8bbf9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/20414d96f391677bf80078aa55baece78b82647d", - "reference": "20414d96f391677bf80078aa55baece78b82647d", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/c2f3ad828596624ca39ea40f83617ef51ca8bbf9", + "reference": "c2f3ad828596624ca39ea40f83617ef51ca8bbf9", "shasum": "" }, "require": { @@ -5404,7 +5404,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.1" }, "funding": [ { @@ -5420,20 +5420,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-11-25T12:02:18+00:00" }, { "name": "symfony/http-foundation", - "version": "v6.4.15", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "9b3165eb2f04aeaa1a5a2cfef73e63fe3b22dff6" + "reference": "431771b7a6f662f1575b3cfc8fd7617aa9864d57" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9b3165eb2f04aeaa1a5a2cfef73e63fe3b22dff6", - "reference": "9b3165eb2f04aeaa1a5a2cfef73e63fe3b22dff6", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/431771b7a6f662f1575b3cfc8fd7617aa9864d57", + "reference": "431771b7a6f662f1575b3cfc8fd7617aa9864d57", "shasum": "" }, "require": { @@ -5481,7 +5481,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.4.15" + "source": "https://github.com/symfony/http-foundation/tree/v6.4.16" }, "funding": [ { @@ -5497,20 +5497,20 @@ "type": "tidelift" } ], - "time": "2024-11-08T16:09:24+00:00" + "time": "2024-11-13T18:58:10+00:00" }, { "name": "symfony/http-kernel", - "version": "v6.4.15", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "b002a5b3947653c5aee3adac2a024ea615fd3ff5" + "reference": "8838b5b21d807923b893ccbfc2cbeda0f1bc00f0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/b002a5b3947653c5aee3adac2a024ea615fd3ff5", - "reference": "b002a5b3947653c5aee3adac2a024ea615fd3ff5", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/8838b5b21d807923b893ccbfc2cbeda0f1bc00f0", + "reference": "8838b5b21d807923b893ccbfc2cbeda0f1bc00f0", "shasum": "" }, "require": { @@ -5595,7 +5595,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v6.4.15" + "source": "https://github.com/symfony/http-kernel/tree/v6.4.16" }, "funding": [ { @@ -5611,7 +5611,7 @@ "type": "tidelift" } ], - "time": "2024-11-13T13:57:37+00:00" + "time": "2024-11-27T12:49:36+00:00" }, { "name": "symfony/intl", @@ -6101,16 +6101,16 @@ }, { "name": "symfony/options-resolver", - "version": "v6.4.13", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "0a62a9f2504a8dd27083f89d21894ceb01cc59db" + "reference": "368128ad168f20e22c32159b9f761e456cec0c78" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/0a62a9f2504a8dd27083f89d21894ceb01cc59db", - "reference": "0a62a9f2504a8dd27083f89d21894ceb01cc59db", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/368128ad168f20e22c32159b9f761e456cec0c78", + "reference": "368128ad168f20e22c32159b9f761e456cec0c78", "shasum": "" }, "require": { @@ -6148,7 +6148,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v6.4.13" + "source": "https://github.com/symfony/options-resolver/tree/v6.4.16" }, "funding": [ { @@ -6164,7 +6164,7 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:18:03+00:00" + "time": "2024-11-20T10:57:02+00:00" }, { "name": "symfony/password-hasher", @@ -6533,16 +6533,16 @@ }, { "name": "symfony/property-info", - "version": "v6.4.15", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "9d7b576bb643c72bf3b60eb8e89c98725d00afd0" + "reference": "e4782ec1c2b6896e820896357f6a3d02249e63eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/9d7b576bb643c72bf3b60eb8e89c98725d00afd0", - "reference": "9d7b576bb643c72bf3b60eb8e89c98725d00afd0", + "url": "https://api.github.com/repos/symfony/property-info/zipball/e4782ec1c2b6896e820896357f6a3d02249e63eb", + "reference": "e4782ec1c2b6896e820896357f6a3d02249e63eb", "shasum": "" }, "require": { @@ -6550,17 +6550,18 @@ "symfony/string": "^5.4|^6.0|^7.0" }, "conflict": { + "doctrine/annotations": "<1.12", "phpdocumentor/reflection-docblock": "<5.2", "phpdocumentor/type-resolver": "<1.5.1", - "symfony/dependency-injection": "<5.4", - "symfony/serializer": "<6.4" + "symfony/dependency-injection": "<5.4|>=6.0,<6.4" }, "require-dev": { + "doctrine/annotations": "^1.12|^2", "phpdocumentor/reflection-docblock": "^5.2", "phpstan/phpdoc-parser": "^1.0|^2.0", "symfony/cache": "^5.4|^6.0|^7.0", "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/serializer": "^6.4|^7.0" + "symfony/serializer": "^5.4|^6.4|^7.0" }, "type": "library", "autoload": { @@ -6596,7 +6597,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v6.4.15" + "source": "https://github.com/symfony/property-info/tree/v6.4.16" }, "funding": [ { @@ -6612,7 +6613,7 @@ "type": "tidelift" } ], - "time": "2024-11-07T16:39:46+00:00" + "time": "2024-11-27T10:18:02+00:00" }, { "name": "symfony/proxy-manager-bridge", @@ -6683,16 +6684,16 @@ }, { "name": "symfony/routing", - "version": "v6.4.13", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "640a74250d13f9c30d5ca045b6aaaabcc8215278" + "reference": "91e02e606b4b705c2f4fb42f7e7708b7923a3220" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/640a74250d13f9c30d5ca045b6aaaabcc8215278", - "reference": "640a74250d13f9c30d5ca045b6aaaabcc8215278", + "url": "https://api.github.com/repos/symfony/routing/zipball/91e02e606b4b705c2f4fb42f7e7708b7923a3220", + "reference": "91e02e606b4b705c2f4fb42f7e7708b7923a3220", "shasum": "" }, "require": { @@ -6746,7 +6747,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v6.4.13" + "source": "https://github.com/symfony/routing/tree/v6.4.16" }, "funding": [ { @@ -6762,7 +6763,7 @@ "type": "tidelift" } ], - "time": "2024-10-01T08:30:56+00:00" + "time": "2024-11-13T15:31:34+00:00" }, { "name": "symfony/runtime", @@ -6957,16 +6958,16 @@ }, { "name": "symfony/security-core", - "version": "v6.4.13", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "bbd1a919aec8696a95bf8749d5577fbe74de973c" + "reference": "19cdb7de86e556202ab16e0cffd1a97348231bc0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/bbd1a919aec8696a95bf8749d5577fbe74de973c", - "reference": "bbd1a919aec8696a95bf8749d5577fbe74de973c", + "url": "https://api.github.com/repos/symfony/security-core/zipball/19cdb7de86e556202ab16e0cffd1a97348231bc0", + "reference": "19cdb7de86e556202ab16e0cffd1a97348231bc0", "shasum": "" }, "require": { @@ -7023,7 +7024,7 @@ "description": "Symfony Security Component - Core Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-core/tree/v6.4.13" + "source": "https://github.com/symfony/security-core/tree/v6.4.16" }, "funding": [ { @@ -7039,7 +7040,7 @@ "type": "tidelift" } ], - "time": "2024-10-25T15:07:50+00:00" + "time": "2024-11-27T09:48:51+00:00" }, { "name": "symfony/security-csrf", @@ -7297,16 +7298,16 @@ }, { "name": "symfony/service-contracts", - "version": "v3.5.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", - "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", "shasum": "" }, "require": { @@ -7360,7 +7361,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" }, "funding": [ { @@ -7376,7 +7377,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/stopwatch", @@ -7623,16 +7624,16 @@ }, { "name": "symfony/translation-contracts", - "version": "v3.5.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a" + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", - "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c", + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c", "shasum": "" }, "require": { @@ -7681,7 +7682,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1" }, "funding": [ { @@ -7697,20 +7698,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/twig-bridge", - "version": "v6.4.13", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "ec3511eef0576f378b2758da9e1c157086babd59" + "reference": "32ec012ed4f6426441a66014471bdb26674744be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/ec3511eef0576f378b2758da9e1c157086babd59", - "reference": "ec3511eef0576f378b2758da9e1c157086babd59", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/32ec012ed4f6426441a66014471bdb26674744be", + "reference": "32ec012ed4f6426441a66014471bdb26674744be", "shasum": "" }, "require": { @@ -7790,7 +7791,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v6.4.13" + "source": "https://github.com/symfony/twig-bridge/tree/v6.4.16" }, "funding": [ { @@ -7806,7 +7807,7 @@ "type": "tidelift" } ], - "time": "2024-10-25T15:07:50+00:00" + "time": "2024-11-25T11:59:11+00:00" }, { "name": "symfony/twig-bundle", @@ -7968,16 +7969,16 @@ }, { "name": "symfony/ux-twig-component", - "version": "v2.21.0", + "version": "v2.22.0", "source": { "type": "git", "url": "https://github.com/symfony/ux-twig-component.git", - "reference": "5b60b239fffcb04fc8bdb2a5a4001d19442d575d" + "reference": "03177a494399fbdcbb1f5f2aee017ccf8df581d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-twig-component/zipball/5b60b239fffcb04fc8bdb2a5a4001d19442d575d", - "reference": "5b60b239fffcb04fc8bdb2a5a4001d19442d575d", + "url": "https://api.github.com/repos/symfony/ux-twig-component/zipball/03177a494399fbdcbb1f5f2aee017ccf8df581d9", + "reference": "03177a494399fbdcbb1f5f2aee017ccf8df581d9", "shasum": "" }, "require": { @@ -8004,8 +8005,8 @@ "type": "symfony-bundle", "extra": { "thanks": { - "name": "symfony/ux", - "url": "https://github.com/symfony/ux" + "url": "https://github.com/symfony/ux", + "name": "symfony/ux" } }, "autoload": { @@ -8031,7 +8032,7 @@ "twig" ], "support": { - "source": "https://github.com/symfony/ux-twig-component/tree/v2.21.0" + "source": "https://github.com/symfony/ux-twig-component/tree/v2.22.0" }, "funding": [ { @@ -8047,20 +8048,20 @@ "type": "tidelift" } ], - "time": "2024-10-05T22:11:16+00:00" + "time": "2024-11-23T06:59:34+00:00" }, { "name": "symfony/validator", - "version": "v6.4.15", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "7541055cdaf54ff95f0735bf703d313374e8b20b" + "reference": "9b0d1988b56511706bc91d96ead39acd77aaf34d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/7541055cdaf54ff95f0735bf703d313374e8b20b", - "reference": "7541055cdaf54ff95f0735bf703d313374e8b20b", + "url": "https://api.github.com/repos/symfony/validator/zipball/9b0d1988b56511706bc91d96ead39acd77aaf34d", + "reference": "9b0d1988b56511706bc91d96ead39acd77aaf34d", "shasum": "" }, "require": { @@ -8128,7 +8129,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v6.4.15" + "source": "https://github.com/symfony/validator/tree/v6.4.16" }, "funding": [ { @@ -8144,7 +8145,7 @@ "type": "tidelift" } ], - "time": "2024-11-08T15:28:48+00:00" + "time": "2024-11-27T09:48:51+00:00" }, { "name": "symfony/var-dumper", @@ -8648,7 +8649,7 @@ }, { "name": "twig/extra-bundle", - "version": "v3.15.0", + "version": "v3.16.0", "source": { "type": "git", "url": "https://github.com/twigphp/twig-extra-bundle.git", @@ -8706,7 +8707,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.15.0" + "source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.16.0" }, "funding": [ { @@ -8722,16 +8723,16 @@ }, { "name": "twig/twig", - "version": "v3.15.0", + "version": "v3.16.0", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "2d5b3964cc21d0188633d7ddce732dc8e874db02" + "reference": "475ad2dc97d65d8631393e721e7e44fb544f0561" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/2d5b3964cc21d0188633d7ddce732dc8e874db02", - "reference": "2d5b3964cc21d0188633d7ddce732dc8e874db02", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/475ad2dc97d65d8631393e721e7e44fb544f0561", + "reference": "475ad2dc97d65d8631393e721e7e44fb544f0561", "shasum": "" }, "require": { @@ -8742,6 +8743,7 @@ "symfony/polyfill-php81": "^1.29" }, "require-dev": { + "phpstan/phpstan": "^2.0", "psr/container": "^1.0|^2.0", "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" }, @@ -8785,7 +8787,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.15.0" + "source": "https://github.com/twigphp/Twig/tree/v3.16.0" }, "funding": [ { @@ -8797,7 +8799,7 @@ "type": "tidelift" } ], - "time": "2024-11-17T15:59:19+00:00" + "time": "2024-11-29T08:27:05+00:00" }, { "name": "ua-parser/uap-php", @@ -9493,12 +9495,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "b33a18b5d222c63472a4b41f6fa3e15e591c9595" + "reference": "fff26f7a91a7458bf6eea5afdd71b4aba1f1d3ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/b33a18b5d222c63472a4b41f6fa3e15e591c9595", - "reference": "b33a18b5d222c63472a4b41f6fa3e15e591c9595", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/fff26f7a91a7458bf6eea5afdd71b4aba1f1d3ea", + "reference": "fff26f7a91a7458bf6eea5afdd71b4aba1f1d3ea", "shasum": "" }, "conflict": { @@ -10079,6 +10081,7 @@ "socialiteproviders/steam": "<1.1", "spatie/browsershot": "<3.57.4", "spatie/image-optimizer": "<1.7.3", + "spencer14420/sp-php-email-handler": "<1", "spipu/html2pdf": "<5.2.8", "spoon/library": "<1.4.1", "spoonity/tcpdf": "<6.2.22", @@ -10149,7 +10152,7 @@ "t3s/content-consent": "<1.0.3|>=2,<2.0.2", "tastyigniter/tastyigniter": "<3.3", "tcg/voyager": "<=1.4", - "tecnickcom/tcpdf": "<=6.7.4", + "tecnickcom/tcpdf": "<=6.7.5", "terminal42/contao-tablelookupwizard": "<3.3.5", "thelia/backoffice-default-template": ">=2.1,<2.1.2", "thelia/thelia": ">=2.1,<2.1.3", @@ -10327,7 +10330,7 @@ "type": "tidelift" } ], - "time": "2024-11-19T21:04:39+00:00" + "time": "2024-11-27T22:05:07+00:00" }, { "name": "symfony/browser-kit", @@ -10538,16 +10541,16 @@ }, { "name": "symfony/dom-crawler", - "version": "v6.4.13", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "ae074dffb018c37a57071990d16e6152728dd972" + "reference": "4304e6ad5c894a9c72831ad459f627bfd35d766d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/ae074dffb018c37a57071990d16e6152728dd972", - "reference": "ae074dffb018c37a57071990d16e6152728dd972", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/4304e6ad5c894a9c72831ad459f627bfd35d766d", + "reference": "4304e6ad5c894a9c72831ad459f627bfd35d766d", "shasum": "" }, "require": { @@ -10585,7 +10588,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v6.4.13" + "source": "https://github.com/symfony/dom-crawler/tree/v6.4.16" }, "funding": [ { @@ -10601,7 +10604,7 @@ "type": "tidelift" } ], - "time": "2024-10-25T15:07:50+00:00" + "time": "2024-11-13T15:06:22+00:00" }, { "name": "symfony/maker-bundle", @@ -10786,16 +10789,16 @@ }, { "name": "symfony/web-profiler-bundle", - "version": "v6.4.14", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "bfbade623f1cc7f1e243ce5488af33861a8f5be7" + "reference": "2d58fd04ac0d3c6279cadd0105959083ef1d7f5b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/bfbade623f1cc7f1e243ce5488af33861a8f5be7", - "reference": "bfbade623f1cc7f1e243ce5488af33861a8f5be7", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/2d58fd04ac0d3c6279cadd0105959083ef1d7f5b", + "reference": "2d58fd04ac0d3c6279cadd0105959083ef1d7f5b", "shasum": "" }, "require": { @@ -10848,7 +10851,7 @@ "dev" ], "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.4.14" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.4.16" }, "funding": [ { @@ -10864,7 +10867,7 @@ "type": "tidelift" } ], - "time": "2024-11-04T11:33:53+00:00" + "time": "2024-11-19T10:11:25+00:00" } ], "aliases": [], diff --git a/config/packages/framework.yaml b/config/packages/framework.yaml index e3b74d35..522808a2 100644 --- a/config/packages/framework.yaml +++ b/config/packages/framework.yaml @@ -18,6 +18,11 @@ framework: php_errors: log: true + serializer: + name_converter: 'serializer.name_converter.camel_case_to_snake_case' + default_context: + skip_null_values: true + when@test: framework: test: true diff --git a/config/services.yaml b/config/services.yaml index b59088f2..8a2081b1 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -39,3 +39,8 @@ services: App\Service\CacheWarmupService: arguments: $baseUrl: '%env(BASE_URL)%' + + serializer.normalizer.json_serializable: + class: Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer + tags: + - { name: 'serializer.normalizer', priority: -2048 } diff --git a/src/Entity/MajorVersion.php b/src/Entity/MajorVersion.php index 2042c8ed..6d505445 100644 --- a/src/Entity/MajorVersion.php +++ b/src/Entity/MajorVersion.php @@ -184,7 +184,13 @@ public function setReleases(Collection $releases): void */ public function getReleases(): Collection { - return $this->releases; + $sorted = $this->releases->toArray(); + usort($sorted, function ($a, $b) { + return version_compare($a->getVersion(), $b->getVersion()); + }); + $sorted = array_reverse($sorted); + + return new ArrayCollection($sorted); } public function setTitle(string $title): void @@ -376,14 +382,9 @@ public function jsonSerialize(): array $releaseData[$release->getVersion()] = $release; } - uksort( - $releaseData, - static fn(string $a, string $b): int => version_compare($a, $b) - ); - $desc = array_reverse($releaseData); $latest = $this->getLatestRelease(); return [ - 'releases' => $desc, + 'releases' => $releaseData, 'latest' => $latest !== null ? $latest->getVersion() : '', 'stable' => $latest !== null ? $latest->getVersion() : '', 'active' => $this->isActive(), diff --git a/src/Entity/Release.php b/src/Entity/Release.php index d5c87709..dccc7050 100644 --- a/src/Entity/Release.php +++ b/src/Entity/Release.php @@ -30,7 +30,9 @@ use App\Repository\ReleaseRepository; use Doctrine\ORM\Mapping as ORM; use OpenApi\Attributes as OA; +use Symfony\Component\Serializer\Attribute\Context; use Symfony\Component\Serializer\Attribute\Groups; +use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; use Symfony\Component\Validator\Constraints as Assert; #[OA\Schema(description: 'TYPO3 release', title: 'Release')] @@ -39,9 +41,7 @@ class Release implements \JsonSerializable, \Stringable { #[OA\Property(example: '8.7.12')] - #[Assert\Regex( - '/^(\d+\.\d+\.\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/' - )] + #[Assert\Regex('/^(\d+\.\d+\.\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/')] #[ORM\Id] #[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING)] #[Groups(['content', 'data'])] @@ -49,7 +49,8 @@ class Release implements \JsonSerializable, \Stringable #[OA\Property(example: '2017-12-12T16:48:22+00:00')] #[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATETIME_MUTABLE)] - #[Groups(['data', 'content'])] + #[Groups(['content', 'data'])] + #[Context([DateTimeNormalizer::FORMAT_KEY => 'Y-m-d\\TH:i:sP'])] private \DateTimeInterface $date; #[Assert\Choice(callback: [ReleaseTypeEnum::class, 'getAvailableOptions'])] @@ -60,7 +61,7 @@ class Release implements \JsonSerializable, \Stringable #[OA\Property(example: true)] #[Assert\Type('boolean')] #[ORM\Column(type: \Doctrine\DBAL\Types\Types::BOOLEAN, options: ['default' => 0])] - #[Groups(['data', 'content'])] + #[Groups(['content', 'data'])] private bool $elts = false; #[Assert\Valid] diff --git a/tests/Functional/Controller/Api/ApiCase.php b/tests/Functional/Controller/Api/ApiCase.php index 15594483..d8b4d3ad 100644 --- a/tests/Functional/Controller/Api/ApiCase.php +++ b/tests/Functional/Controller/Api/ApiCase.php @@ -98,4 +98,99 @@ protected function createRequirementFromJson(string $filePath, string $majorVers return $this->client->getResponse(); } + + /** + * @param array $expectedStructure + * @param array $actualArray + */ + protected function assertArrayStructure(array $expectedStructure, array $actualArray): void + { + // If the expected structure is an array (root level as list) + if (isset($expectedStructure[0])) { + self::assertIsArray($actualArray); + + // Validate each item in the list + foreach ($actualArray as $item) { + self::assertIsArray($item); + /** @var array> $expectedStructure */ + /** @var array $item */ + $this->assertArrayStructure($expectedStructure[0], $item); + } + } else { + // Validate each key in the structure + foreach ($expectedStructure as $key => $value) { + $isOptional = is_string($key) && str_starts_with($key, '?'); + $actualKey = $isOptional ? ltrim($key, '?') : $key; + + if (array_key_exists($actualKey, $actualArray)) { + // If the key exists, validate its structure or type + if (is_array($value)) { + if ($this->isListStructure($value)) { + // Validate a list of items + self::assertIsArray($actualArray[$actualKey]); + foreach ($actualArray[$actualKey] as $item) { + /** @var array> $value */ + /** @var array $item */ + $this->assertArrayStructure($value[0], $item); + } + } else { + // Validate a single nested structure + /** @var array $value */ + /** @var array> $actualArray */ + $this->assertArrayStructure($value, $actualArray[$actualKey]); + } + } else { + /** @var string $value */ + $this->assertIsType($value, $actualArray[$actualKey], "Key '$actualKey' does not match the expected type."); + } + } elseif (!$isOptional) { + // If the key is not optional, it must exist + self::fail("Missing required key: $actualKey"); + } + } + } + } + + protected function assertIsType(string $type, mixed $value, string $message): void + { + switch ($type) { + case 'string': + self::assertIsString($value, $message); + break; + case 'boolean': + self::assertIsBool($value, $message); + break; + case 'integer': + self::assertIsInt($value, $message); + break; + case 'float': + self::assertIsFloat($value, $message); // New check for float + break; + case 'array': + self::assertIsArray($value, $message); + break; + case 'datetime': + self::assertIsString($value, $message); + self::assertValidDateTime($value, $message); + break; + default: + self::fail("Unsupported type: $type"); + } + } + + protected function assertValidDateTime(string $value, string $message): void + { + // ISO 8601 datetime regex + $pattern = '/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(\+\d{2}:\d{2}|Z)$/'; + self::assertMatchesRegularExpression($pattern, $value, $message); + } + + /** + * @param array $structure + */ + protected function isListStructure(array $structure): bool + { + // Determines if the given structure is a list of items (e.g., [ { ... } ]) + return count($structure) === 1 && array_keys($structure) === [0] && is_array($structure[0]); + } } diff --git a/tests/Functional/Controller/Api/MajorVersion/ReleaseControllerTest.php b/tests/Functional/Controller/Api/MajorVersion/ReleaseControllerTest.php new file mode 100644 index 00000000..c085f11e --- /dev/null +++ b/tests/Functional/Controller/Api/MajorVersion/ReleaseControllerTest.php @@ -0,0 +1,194 @@ +addFixture(new MajorVersionFixtures()); + $this->addFixture(new ReleaseFixtures()); + $this->addFixture(new RequirementFixtures()); + $this->executeFixtures(); + + $this->client->request('GET', '/api/v1/major/10/release/'); + + $response = $this->client->getResponse(); + $responseContent = json_decode((string)$response->getContent(), true, 512, JSON_THROW_ON_ERROR); + + self::assertIsArray($responseContent); + $this->assertArrayStructure( + [ + [ + 'version' => 'string', + 'date' => 'datetime', + 'type' => 'string', + 'elts' => 'boolean', + 'tar_package' => [ + '?md5sum' => 'string', + '?sha1sum' => 'string', + '?sha256sum' => 'string', + ], + 'zip_package' => [ + '?md5sum' => 'string', + '?sha1sum' => 'string', + '?sha256sum' => 'string', + ], + ], + ], + $responseContent + ); + } + + /** + * @test + */ + public function getLatestReleaseByMajorVersionStructureTest(): void + { + $this->addFixture(new MajorVersionFixtures()); + $this->addFixture(new ReleaseFixtures()); + $this->addFixture(new RequirementFixtures()); + $this->executeFixtures(); + + $this->client->request('GET', '/api/v1/major/10/release/latest'); + + $response = $this->client->getResponse(); + $responseContent = json_decode((string)$response->getContent(), true, 512, JSON_THROW_ON_ERROR); + + self::assertIsArray($responseContent); + $this->assertArrayStructure( + [ + 'version' => 'string', + 'date' => 'datetime', + 'type' => 'string', + 'elts' => 'boolean', + 'tar_package' => [ + '?md5sum' => 'string', + '?sha1sum' => 'string', + '?sha256sum' => 'string', + ], + 'zip_package' => [ + '?md5sum' => 'string', + '?sha1sum' => 'string', + '?sha256sum' => 'string', + ], + ], + $responseContent + ); + } + + /** + * @test + */ + public function getLatestSecurityReleaseByMajorVersionStructureTest(): void + { + $this->addFixture(new MajorVersionFixtures()); + $this->addFixture(new ReleaseFixtures()); + $this->addFixture(new RequirementFixtures()); + $this->executeFixtures(); + + $this->client->request('GET', '/api/v1/major/10/release/latest/security'); + + $response = $this->client->getResponse(); + $responseContent = json_decode((string)$response->getContent(), true, 512, JSON_THROW_ON_ERROR); + + self::assertIsArray($responseContent); + $this->assertArrayStructure( + [ + 'version' => 'string', + 'date' => 'datetime', + 'type' => 'string', + 'elts' => 'boolean', + 'tar_package' => [ + '?md5sum' => 'string', + '?sha1sum' => 'string', + '?sha256sum' => 'string', + ], + 'zip_package' => [ + '?md5sum' => 'string', + '?sha1sum' => 'string', + '?sha256sum' => 'string', + ], + ], + $responseContent + ); + } + + /** + * @test + */ + public function getLatestReleaseContentByMajorVersionStructureTest(): void + { + $this->addFixture(new MajorVersionFixtures()); + $this->addFixture(new ReleaseFixtures()); + $this->addFixture(new RequirementFixtures()); + $this->executeFixtures(); + + $this->client->request('GET', '/api/v1/major/10/release/latest/content'); + + $response = $this->client->getResponse(); + $responseContent = json_decode((string)$response->getContent(), true, 512, JSON_THROW_ON_ERROR); + + self::assertIsArray($responseContent); + $this->assertArrayStructure( + [ + 'version' => 'string', + 'date' => 'datetime', + 'elts' => 'boolean', + 'release_notes' => [ + 'news_link' => 'string', + 'news' => 'string', + 'upgrading_instructions' => 'string', + 'changes' => 'string', + '?legacy_content' => 'string', + ], + '?checksums' => [ + 'tar' => [ + '?sha1' => 'string', + '?md5' => 'string', + '?sha256' => 'string', + ], + 'zip' => [ + '?sha1' => 'string', + '?md5' => 'string', + '?sha256' => 'string', + ], + ], + '?urls' => [ + 'tar' => 'string', + 'zip' => 'string', + ], + ], + $responseContent + ); + } +} diff --git a/tests/Functional/Controller/Api/MajorVersion/RequirementsControllerTest.php b/tests/Functional/Controller/Api/MajorVersion/RequirementsControllerTest.php index 26adb726..99c1fb4d 100644 --- a/tests/Functional/Controller/Api/MajorVersion/RequirementsControllerTest.php +++ b/tests/Functional/Controller/Api/MajorVersion/RequirementsControllerTest.php @@ -23,6 +23,9 @@ namespace App\Tests\Functional\Controller\Api\MajorVersion; +use App\DataFixtures\MajorVersionFixtures; +use App\DataFixtures\ReleaseFixtures; +use App\DataFixtures\RequirementFixtures; use App\Tests\Functional\Controller\Api\ApiCase; use Symfony\Component\HttpFoundation\Response; @@ -53,4 +56,33 @@ public function addRequirementAuthorized(): void self::assertSame(Response::HTTP_CREATED, $response->getStatusCode()); self::assertSame(['status' => 'success', 'Location' => '/v1/api/major/10'], $this->decodeResponse($response)); } + + /** + * @test + */ + public function getRequirementsByMajorVersionStructureTest(): void + { + $this->addFixture(new MajorVersionFixtures()); + $this->addFixture(new ReleaseFixtures()); + $this->addFixture(new RequirementFixtures()); + $this->executeFixtures(); + + $this->client->request('GET', '/api/v1/major/10/requirements'); + + $response = $this->client->getResponse(); + $responseContent = json_decode((string)$response->getContent(), true, 512, JSON_THROW_ON_ERROR); + + self::assertIsArray($responseContent); + $this->assertArrayStructure( + [ + [ + 'category' => 'string', + 'name' => 'string', + '?min' => 'string', + '?max' => 'string', + ], + ], + $responseContent + ); + } } diff --git a/tests/Functional/Controller/Api/MajorVersionControllerTest.php b/tests/Functional/Controller/Api/MajorVersionControllerTest.php index 46a5ee38..0442d099 100644 --- a/tests/Functional/Controller/Api/MajorVersionControllerTest.php +++ b/tests/Functional/Controller/Api/MajorVersionControllerTest.php @@ -23,6 +23,9 @@ namespace App\Tests\Functional\Controller\Api; +use App\DataFixtures\MajorVersionFixtures; +use App\DataFixtures\ReleaseFixtures; +use App\DataFixtures\RequirementFixtures; use Symfony\Component\HttpFoundation\Response; class MajorVersionControllerTest extends ApiCase @@ -46,4 +49,90 @@ public function createMajorVersionAuthorized(): void self::assertSame(Response::HTTP_CREATED, $response->getStatusCode()); self::assertSame(['status' => 'success', 'Location' => '/v1/api/major/10'], $this->decodeResponse($response)); } + + /** + * @test + */ + public function getMajorReleasesStructureTest(): void + { + $this->addFixture(new MajorVersionFixtures()); + $this->addFixture(new ReleaseFixtures()); + $this->addFixture(new RequirementFixtures()); + $this->executeFixtures(); + + $this->client->request('GET', '/api/v1/major/'); + + $response = $this->client->getResponse(); + $responseContent = json_decode((string)$response->getContent(), true, 512, JSON_THROW_ON_ERROR); + + self::assertIsArray($responseContent); + $this->assertArrayStructure( + [ + [ + 'version' => 'float', + 'title' => 'string', + 'subtitle' => 'string', + 'description' => 'string', + 'release_date' => 'datetime', + '?regular_maintenance_until' => 'datetime', + '?maintained_until' => 'datetime', + '?elts_until' => 'datetime', + 'requirements' => [ + [ + 'category' => 'string', + 'name' => 'string', + '?min' => 'string', + '?max' => 'string', + ], + ], + '?lts' => 'float', + '?active' => 'boolean', + '?elts' => 'boolean', + ], + ], + $responseContent + ); + } + + /** + * @test + */ + public function getMajorReleaseWithVersionStructureTest(): void + { + $this->addFixture(new MajorVersionFixtures()); + $this->addFixture(new ReleaseFixtures()); + $this->addFixture(new RequirementFixtures()); + $this->executeFixtures(); + + $this->client->request('GET', '/api/v1/major/10'); + + $response = $this->client->getResponse(); + $responseContent = json_decode((string)$response->getContent(), true, 512, JSON_THROW_ON_ERROR); + + self::assertIsArray($responseContent); + $this->assertArrayStructure( + [ + 'version' => 'float', + 'title' => 'string', + 'subtitle' => 'string', + 'description' => 'string', + 'release_date' => 'datetime', + '?regular_maintenance_until' => 'datetime', + '?maintained_until' => 'datetime', + '?elts_until' => 'datetime', + 'requirements' => [ + [ + 'category' => 'string', + 'name' => 'string', + '?min' => 'string', + '?max' => 'string', + ], + ], + '?lts' => 'float', + '?active' => 'boolean', + '?elts' => 'boolean', + ], + $responseContent + ); + } } diff --git a/tests/Functional/Controller/Api/ReleaseControllerTest.php b/tests/Functional/Controller/Api/ReleaseControllerTest.php index c145ab3d..8b59055d 100644 --- a/tests/Functional/Controller/Api/ReleaseControllerTest.php +++ b/tests/Functional/Controller/Api/ReleaseControllerTest.php @@ -23,6 +23,9 @@ namespace App\Tests\Functional\Controller\Api; +use App\DataFixtures\MajorVersionFixtures; +use App\DataFixtures\ReleaseFixtures; +use App\DataFixtures\RequirementFixtures; use Symfony\Component\HttpFoundation\Response; class ReleaseControllerTest extends ApiCase @@ -58,4 +61,113 @@ public function createReleaseAuthorized(): void $this->decodeResponse($response) ); } + + /** + * @test + */ + public function getReleaseStructureTest(): void + { + $this->addFixture(new MajorVersionFixtures()); + $this->addFixture(new ReleaseFixtures()); + $this->addFixture(new RequirementFixtures()); + $this->executeFixtures(); + + $this->client->request('GET', '/api/v1/release/'); + + $response = $this->client->getResponse(); + $responseContent = json_decode((string)$response->getContent(), true, 512, JSON_THROW_ON_ERROR); + + self::assertIsArray($responseContent); + $this->assertArrayStructure( + [ + [ + 'version' => 'string', + 'date' => 'datetime', + 'type' => 'string', + 'elts' => 'boolean', + 'tar_package' => [ + '?md5sum' => 'string', + '?sha1sum' => 'string', + '?sha256sum' => 'string', + ], + 'zip_package' => [ + '?md5sum' => 'string', + '?sha1sum' => 'string', + '?sha256sum' => 'string', + ], + ], + ], + $responseContent + ); + } + + /** + * @test + */ + public function getReleaseWithVersionStructureTest(): void + { + $this->addFixture(new MajorVersionFixtures()); + $this->addFixture(new ReleaseFixtures()); + $this->addFixture(new RequirementFixtures()); + $this->executeFixtures(); + + $this->client->request('GET', '/api/v1/release/10.0.0'); + + $response = $this->client->getResponse(); + $responseContent = json_decode((string)$response->getContent(), true, 512, JSON_THROW_ON_ERROR); + + self::assertIsArray($responseContent); + $this->assertArrayStructure( + [ + 'version' => 'string', + 'date' => 'datetime', + 'type' => 'string', + 'elts' => 'boolean', + 'tar_package' => [ + '?md5sum' => 'string', + '?sha1sum' => 'string', + '?sha256sum' => 'string', + ], + 'zip_package' => [ + '?md5sum' => 'string', + '?sha1sum' => 'string', + '?sha256sum' => 'string', + ], + ], + $responseContent + ); + } + + /** + * @test + */ + public function getContentForVersionStructureTest(): void + { + $this->addFixture(new MajorVersionFixtures()); + $this->addFixture(new ReleaseFixtures()); + $this->addFixture(new RequirementFixtures()); + $this->executeFixtures(); + + $this->client->request('GET', '/api/v1/release/10.0.0/content'); + + $response = $this->client->getResponse(); + $responseContent = json_decode((string)$response->getContent(), true, 512, JSON_THROW_ON_ERROR); + + self::assertIsArray($responseContent); + $this->assertArrayStructure( + [ + 'version' => 'string', + 'date' => 'datetime', + 'elts' => 'boolean', + 'release_notes' => [ + 'news_link' => 'string', + 'news' => 'string', + 'upgrading_instructions' => 'string', + 'changes' => 'string', + '?legacy_content' => 'string', + ], + ], + $responseContent + ); + } } diff --git a/tests/Unit/phpunit.xml b/tests/Unit/phpunit.xml index 3d247391..5bd48039 100644 --- a/tests/Unit/phpunit.xml +++ b/tests/Unit/phpunit.xml @@ -14,6 +14,10 @@ stopOnFailure="false" bootstrap="../bootstrap.php" > + + + + ./ From 89d6825dbf2338fd3f14a977c5b5b78667e9fca0 Mon Sep 17 00:00:00 2001 From: Benjamin Kott Date: Mon, 2 Dec 2024 12:19:06 +0100 Subject: [PATCH 2/3] [TASK] Add tests as requirement for deployment (#476) --- .github/workflows/continuous-integration.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 990c5c7b..36026d02 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -279,6 +279,7 @@ jobs: - validation - php_coding_standards - php_stan + - tests if: (github.ref == 'refs/heads/production') && github.event_name == 'push' && (github.repository == 'TYPO3/get.typo3.org') uses: ./.github/workflows/deployment.yml secrets: From cac345e7642d58ad3c76ae607557c10bb0b6779c Mon Sep 17 00:00:00 2001 From: Lina Wolf <48202465+linawolf@users.noreply.github.com> Date: Mon, 2 Dec 2024 12:20:29 +0100 Subject: [PATCH 3/3] [FEATURE] Demonstrate how to change FSC output in site package tutorial package (#475) --- .../Private/ContentElements/Partials/.gitkeep | 1 - .../Partials/Media/Rendering/Image.html | 3 +++ .../ContentElements/Templates/.gitkeep | 1 - .../Templates/MenuSitemap.html | 24 +++++++++++++++++++ .../Templates/MenuSubpages.html | 18 ++++++++++++++ 5 files changed, 45 insertions(+), 2 deletions(-) delete mode 100644 resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Partials/.gitkeep create mode 100644 resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Partials/Media/Rendering/Image.html delete mode 100644 resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Templates/.gitkeep create mode 100644 resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Templates/MenuSitemap.html create mode 100644 resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Templates/MenuSubpages.html diff --git a/resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Partials/.gitkeep b/resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Partials/.gitkeep deleted file mode 100644 index 8b137891..00000000 --- a/resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Partials/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Partials/Media/Rendering/Image.html b/resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Partials/Media/Rendering/Image.html new file mode 100644 index 00000000..d0a7d922 --- /dev/null +++ b/resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Partials/Media/Rendering/Image.html @@ -0,0 +1,3 @@ + + + diff --git a/resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Templates/.gitkeep b/resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Templates/.gitkeep deleted file mode 100644 index 8b137891..00000000 --- a/resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Templates/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Templates/MenuSitemap.html b/resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Templates/MenuSitemap.html new file mode 100644 index 00000000..66c50484 --- /dev/null +++ b/resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Templates/MenuSitemap.html @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + diff --git a/resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Templates/MenuSubpages.html b/resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Templates/MenuSubpages.html new file mode 100644 index 00000000..ff759904 --- /dev/null +++ b/resources/packages/site_package_tutorial/13.4/src/Resources/Private/ContentElements/Templates/MenuSubpages.html @@ -0,0 +1,18 @@ + + + + + + + + + +