From ca7cf8463e2850451a2b3b1b9d636df278b43b52 Mon Sep 17 00:00:00 2001 From: Dan Wallis Date: Sun, 24 Jul 2022 18:28:19 +0100 Subject: [PATCH 1/3] Sort allow-plugins and preferred-install properly --- src/Vendor/Composer/ConfigHashNormalizer.php | 24 +- .../Composer/ConfigHashNormalizerTest.php | 215 +++++++++++++++--- 2 files changed, 188 insertions(+), 51 deletions(-) diff --git a/src/Vendor/Composer/ConfigHashNormalizer.php b/src/Vendor/Composer/ConfigHashNormalizer.php index 6c9b01be..bab617e6 100644 --- a/src/Vendor/Composer/ConfigHashNormalizer.php +++ b/src/Vendor/Composer/ConfigHashNormalizer.php @@ -24,15 +24,6 @@ final class ConfigHashNormalizer implements Normalizer 'scripts-descriptions', ]; - /** - * @see https://getcomposer.org/doc/06-config.md#allow-plugins - * @see https://getcomposer.org/doc/06-config.md#preferred-install - */ - private const PROPERTY_PATHS_THAT_SHOULD_NOT_BE_SORTED = [ - 'config.allow-plugins', - 'config.preferred-install', - ]; - public function normalize(Json $json): Json { $decoded = $json->decoded(); @@ -72,10 +63,6 @@ private static function sortByKey( string $propertyPath, $value ) { - if (\in_array($propertyPath, self::PROPERTY_PATHS_THAT_SHOULD_NOT_BE_SORTED, true)) { - return $value; - } - if (!\is_object($value)) { return $value; } @@ -87,7 +74,16 @@ private static function sortByKey( return $value; } - \ksort($sorted); + // @see https://getcomposer.org/doc/06-config.md#allow-plugins + // @see https://getcomposer.org/doc/06-config.md#preferred-install + \uksort($sorted, static function (string $a, string $b) { + // '*' = ASCII 42 (ie, before all letters, numbers, and dash) + // '~' = ASCII 126 (ie, after all letters, numbers, and dash) + $a = \str_replace('*', '~', $a); + $b = \str_replace('*', '~', $b); + + return \strcmp($a, $b); + }); $names = \array_keys($sorted); diff --git a/test/Unit/Vendor/Composer/ConfigHashNormalizerTest.php b/test/Unit/Vendor/Composer/ConfigHashNormalizerTest.php index b776c6fe..98335d42 100644 --- a/test/Unit/Vendor/Composer/ConfigHashNormalizerTest.php +++ b/test/Unit/Vendor/Composer/ConfigHashNormalizerTest.php @@ -199,7 +199,7 @@ public function testNormalizeSortsConfigHashRecursivelyIfPropertyExists(string $ /** * @see https://getcomposer.org/doc/06-config.md#allow-plugins */ - public function testNormalizeDoesNotSortAllowPluginsInConfig(): void + public function testNormalizeCorrectlySortsAllowPluginsInConfigWithoutWildcards(): void { $json = Json::fromEncoded( <<<'JSON' @@ -207,9 +207,9 @@ public function testNormalizeDoesNotSortAllowPluginsInConfig(): void "config": { "sort-packages": true, "allow-plugins": { - "foo/*": true, - "bar/*": false, - "*": true + "foo/bar": true, + "bar/qux": false, + "foo/baz": false } } } @@ -221,9 +221,9 @@ public function testNormalizeDoesNotSortAllowPluginsInConfig(): void { "config": { "allow-plugins": { - "foo/*": true, - "bar/*": false, - "*": true + "bar/qux": false, + "foo/bar": true, + "foo/baz": false }, "sort-packages": true } @@ -238,17 +238,21 @@ public function testNormalizeDoesNotSortAllowPluginsInConfig(): void self::assertJsonStringEqualsJsonStringNormalized($expected->encoded(), $normalized->encoded()); } - public function testNormalizeSortsAllowPluginsInOtherProperty(): void + /** + * @see https://github.com/ergebnis/composer-normalize/issues/644 + * @see https://getcomposer.org/doc/06-config.md#preferred-install + */ + public function testNormalizeCorrectlySortsPreferredInstallInConfigWithCatchAllWildcardAtEnd(): void { $json = Json::fromEncoded( <<<'JSON' { - "extra": { - "something": { - "allowed-plugins": { - "foo": true, - "bar": false - } + "config": { + "sort-packages": true, + "preferred-install": { + "foo/package-one": "source", + "bar/another-package": "source", + "*": "dist" } } } @@ -258,13 +262,56 @@ public function testNormalizeSortsAllowPluginsInOtherProperty(): void $expected = Json::fromEncoded( <<<'JSON' { - "extra": { - "something": { - "allowed-plugins": { - "bar": false, - "foo": true - } + "config": { + "preferred-install": { + "bar/another-package": "source", + "foo/package-one": "source", + "*": "dist" + }, + "sort-packages": true + } +} +JSON + ); + + $normalizer = new Vendor\Composer\ConfigHashNormalizer(); + + $normalized = $normalizer->normalize($json); + + self::assertJsonStringEqualsJsonStringNormalized($expected->encoded(), $normalized->encoded()); } + + /** + * @see https://github.com/ergebnis/composer-normalize/issues/644 + * @see https://getcomposer.org/doc/06-config.md#preferred-install + */ + public function testNormalizeCorrectlySortsPreferredInstallInConfigWithCatchAllWildcardAtStart(): void + { + $json = Json::fromEncoded( + <<<'JSON' +{ + "config": { + "sort-packages": true, + "preferred-install": { + "*": "dist", + "foo/package-one": "source", + "bar/another-package": "source" + } + } +} +JSON + ); + + $expected = Json::fromEncoded( + <<<'JSON' +{ + "config": { + "preferred-install": { + "bar/another-package": "source", + "foo/package-one": "source", + "*": "dist" + }, + "sort-packages": true } } JSON @@ -281,7 +328,7 @@ public function testNormalizeSortsAllowPluginsInOtherProperty(): void * @see https://github.com/ergebnis/composer-normalize/issues/644 * @see https://getcomposer.org/doc/06-config.md#preferred-install */ - public function testNormalizeDoesNotSortPreferredInstallInConfig(): void + public function testNormalizeCorrectlySortsPreferredInstallInConfigWithCatchAllWildcardInTheMiddle(): void { $json = Json::fromEncoded( <<<'JSON' @@ -289,9 +336,57 @@ public function testNormalizeDoesNotSortPreferredInstallInConfig(): void "config": { "sort-packages": true, "preferred-install": { - "foo/*": "source", - "bar/*": "source", + "foo/package-two": "source", + "foo/package-one": "source", + "*": "dist", + "bar/another-package-2": "source", + "bar/another-package-1": "source" + } + } +} +JSON + ); + + $expected = Json::fromEncoded( + <<<'JSON' +{ + "config": { + "preferred-install": { + "bar/another-package-1": "source", + "bar/another-package-2": "source", + "foo/package-one": "source", + "foo/package-two": "source", "*": "dist" + }, + "sort-packages": true + } +} +JSON + ); + + $normalizer = new Vendor\Composer\ConfigHashNormalizer(); + + $normalized = $normalizer->normalize($json); + + self::assertJsonStringEqualsJsonStringNormalized($expected->encoded(), $normalized->encoded()); + } + + /** + * @see https://github.com/ergebnis/composer-normalize/issues/644 + * @see https://getcomposer.org/doc/06-config.md#preferred-install + */ + public function testNormalizeCorrectlySortsPreferredInstallInConfigWithVendorWildcardAtEnd(): void + { + $json = Json::fromEncoded( + <<<'JSON' +{ + "config": { + "sort-packages": true, + "preferred-install": { + "foo/package-two": "dist", + "foo/package-one": "dist", + "*": "dist", + "foo/*": "source" } } } @@ -303,8 +398,9 @@ public function testNormalizeDoesNotSortPreferredInstallInConfig(): void { "config": { "preferred-install": { + "foo/package-one": "dist", + "foo/package-two": "dist", "foo/*": "source", - "bar/*": "source", "*": "dist" }, "sort-packages": true @@ -320,17 +416,18 @@ public function testNormalizeDoesNotSortPreferredInstallInConfig(): void self::assertJsonStringEqualsJsonStringNormalized($expected->encoded(), $normalized->encoded()); } - public function testNormalizeSortsPreferredInstallInOtherProperty(): void + public function testNormalizeCorrectlySortsPreferredInstallInConfigWhenMoreSpecificAfterWildcard(): void { $json = Json::fromEncoded( <<<'JSON' { - "extra": { - "something": { - "preferred-install": { - "foo": "bar", - "bar": "baz" - } + "config": { + "sort-packages": true, + "preferred-install": { + "foo/*": "source", + "foo/package-two": "dist", + "foo/package-one": "dist", + "*": "dist" } } } @@ -340,18 +437,62 @@ public function testNormalizeSortsPreferredInstallInOtherProperty(): void $expected = Json::fromEncoded( <<<'JSON' { - "extra": { - "something": { - "preferred-install": { - "bar": "baz", - "foo": "bar" - } + "config": { + "preferred-install": { + "foo/package-one": "dist", + "foo/package-two": "dist", + "foo/*": "source", + "*": "dist" + }, + "sort-packages": true + } +} +JSON + ); + + $normalizer = new Vendor\Composer\ConfigHashNormalizer(); + + $normalized = $normalizer->normalize($json); + + self::assertJsonStringEqualsJsonStringNormalized($expected->encoded(), $normalized->encoded()); + } + + public function testNormalizeCorrectlySortsPreferredInstallInConfigWhenMoreSpecificWildcardAfterWildcard(): void + { + $json = Json::fromEncoded( + <<<'JSON' +{ + "config": { + "sort-packages": true, + "preferred-install": { + "foo/something-longer-but-alphabetically-after-package-*": "source", + "foo/*": "dist", + "foo/package-*": "source", + "foo/package-one": "dist", + "*": "dist" } } } JSON ); + $expected = Json::fromEncoded( + <<<'JSON' +{ + "config": { + "preferred-install": { + "foo/package-one": "dist", + "foo/package-*": "source", + "foo/something-longer-but-alphabetically-after-package-*": "source", + "foo/*": "dist", + "*": "dist" + }, + "sort-packages": true + } +} +JSON + ); + $normalizer = new Vendor\Composer\ConfigHashNormalizer(); $normalized = $normalizer->normalize($json); From 7a9fde6e08a6268b2fb2b14d652671a97b5191ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20M=C3=B6ller?= Date: Wed, 10 Aug 2022 08:47:28 +0200 Subject: [PATCH 2/3] Fix: Update CHANGELOG.md --- CHANGELOG.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3853c08..3a3d62e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## Unreleased -For a full diff see [`3.0.0...main`][3.0.0...main]. +For a full diff see [`3.0.1...main`][3.0.1...main]. + +## [`3.0.1`][3.0.1] + +For a full diff see [`3.0.0...3.0.1`][3.0.0...3.0.1]. + +### Fixed + +- Adjusted `ConfigHashNormalizer` to sort keys correctly ([#723]), by [@fredded] ### Changed @@ -385,6 +393,7 @@ For a full diff see [`5d8b3e2...0.1.0`][5d8b3e2...0.1.0]. [2.1.0]: https://github.com/ergebnis/json-normalizer/releases/tag/2.1.0 [2.2.0]: https://github.com/ergebnis/json-normalizer/releases/tag/2.2.0 [3.0.0]: https://github.com/ergebnis/json-normalizer/releases/tag/3.0.0 +[3.0.1]: https://github.com/ergebnis/json-normalizer/releases/tag/3.0.1 [5d8b3e2...0.1.0]: https://github.com/ergebnis/json-normalizer/compare/5d8b3e2...0.1.0 [0.1.0...0.2.0]: https://github.com/ergebnis/json-normalizer/compare/0.1.0...0.2.0 @@ -413,7 +422,8 @@ For a full diff see [`5d8b3e2...0.1.0`][5d8b3e2...0.1.0]. [2.0.0...2.1.0]: https://github.com/ergebnis/json-normalizer/compare/2.0.0...2.1.0 [2.1.0...2.2.0]: https://github.com/ergebnis/json-normalizer/compare/2.1.0...2.2.0 [2.2.0...3.0.0]: https://github.com/ergebnis/json-normalizer/compare/2.2.0...3.0.0 -[3.0.0...main]: https://github.com/ergebnis/json-normalizer/compare/3.0.0...main +[3.0.0...3.0.1]: https://github.com/ergebnis/json-normalizer/compare/3.0.0...3.0.1 +[3.0.1...main]: https://github.com/ergebnis/json-normalizer/compare/3.0.1...main [#1]: https://github.com/ergebnis/json-normalizer/pull/1 [#2]: https://github.com/ergebnis/json-normalizer/pull/2 @@ -504,8 +514,10 @@ For a full diff see [`5d8b3e2...0.1.0`][5d8b3e2...0.1.0]. [#673]: https://github.com/ergebnis/json-normalizer/pull/673 [#697]: https://github.com/ergebnis/json-normalizer/pull/697 [#698]: https://github.com/ergebnis/json-normalizer/pull/698 +[#723]: https://github.com/ergebnis/json-normalizer/pull/723 [@BackEndTea]: https://github.com/BackEndTea [@dependabot]: https://github.com/dependabot [@ergebnis]: https://github.com/ergebnis +[@fredden]: https://github.com/fredden [@localheinz]: https://github.com/localheinz From 1fb20a059da20bb574eaef9a117fef9edd967799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20M=C3=B6ller?= Date: Wed, 10 Aug 2022 08:47:58 +0200 Subject: [PATCH 3/3] Enhancement: Extract method --- src/Vendor/Composer/ConfigHashNormalizer.php | 32 ++++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/Vendor/Composer/ConfigHashNormalizer.php b/src/Vendor/Composer/ConfigHashNormalizer.php index bab617e6..cf209d82 100644 --- a/src/Vendor/Composer/ConfigHashNormalizer.php +++ b/src/Vendor/Composer/ConfigHashNormalizer.php @@ -74,15 +74,11 @@ private static function sortByKey( return $value; } - // @see https://getcomposer.org/doc/06-config.md#allow-plugins - // @see https://getcomposer.org/doc/06-config.md#preferred-install - \uksort($sorted, static function (string $a, string $b) { - // '*' = ASCII 42 (ie, before all letters, numbers, and dash) - // '~' = ASCII 126 (ie, after all letters, numbers, and dash) - $a = \str_replace('*', '~', $a); - $b = \str_replace('*', '~', $b); - - return \strcmp($a, $b); + \uksort($sorted, static function (string $a, string $b): int { + return \strcmp( + self::normalizeKey($a), + self::normalizeKey($b), + ); }); $names = \array_keys($sorted); @@ -101,4 +97,22 @@ private static function sortByKey( }, $sorted, $names), ); } + + /** + * Replaces characters in keys to ensure the correct order. + * + * - '*' = ASCII 42 (i.e., before all letters, numbers, and dash) + * - '~' = ASCII 126 (i.e., after all letters, numbers, and dash) + * + * @see https://getcomposer.org/doc/06-config.md#allow-plugins + * @see https://getcomposer.org/doc/06-config.md#preferred-install + */ + private static function normalizeKey(string $key): string + { + return \str_replace( + '*', + '~', + $key, + ); + } }