├── .gitignore
├── tests
├── fixture
│ ├── invalid-yaml.yml
│ ├── second-level.yml
│ ├── first-and-second-level.yml
│ ├── first-level.yml
│ ├── third-level.yml
│ ├── first-second-and-third-level.yml
│ ├── ok-tagged.yml
│ ├── ok.yml
│ └── symfony-config.yml
└── SortCheckerTest.php
├── bin
├── yaml-sort-checker
└── yaml-sort-checker.php
├── docs
├── yaml-sort-checker-demo.png
└── symfony-config
│ └── yaml-sort-checker.yml
├── .travis.yml
├── src
├── SortCheckResult.php
├── CheckCommand.php
└── SortChecker.php
├── phpunit.xml.dist
├── CHANGELOG.md
├── LICENSE
├── ruleset.xml
├── composer.json
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /composer.lock
3 | /vendor
4 | .phpunit.result.cache
5 |
--------------------------------------------------------------------------------
/tests/fixture/invalid-yaml.yml:
--------------------------------------------------------------------------------
1 | foo:
2 | loo: OK
3 | bar:
4 | data: "hello"
5 |
--------------------------------------------------------------------------------
/bin/yaml-sort-checker:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | messages = $messages;
21 | }
22 |
23 | public function isOk(): bool
24 | {
25 | return count($this->messages) === 0;
26 | }
27 |
28 | /**
29 | * @return string[]
30 | */
31 | public function getMessages(): array
32 | {
33 | return $this->messages;
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 |
15 | tests/
16 |
17 |
18 |
19 |
20 |
21 | ./src
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## 1.5.0 (2020-12-01)
4 | - [#14](https://github.com/mhujer/yaml-sort-checker/pull/14) Allow PHP 8
5 |
6 | ## 1.4.0 (2019-11-22)
7 | - [#12](https://github.com/mhujer/yaml-sort-checker/pull/12) Add support for Symfony 5
8 |
9 | ## 1.3.0 (2019-11-22)
10 | - [#11](https://github.com/mhujer/yaml-sort-checker/pull/11) Add excluded sections support (thanks *@hojgr*)
11 |
12 | ## 1.2.0 (2018-03-26)
13 | - [#9](https://github.com/mhujer/yaml-sort-checker/pull/9) Add excluded sections support (thanks *@OndraM*)
14 |
15 | ## 1.1.0 (2018-03-20)
16 | - [#6](https://github.com/mhujer/yaml-sort-checker/pull/6) Symfony 4 compatibility (thanks *@OndraM*)
17 |
18 | ## 1.0.0 (2017-01-28)
19 | - initial release
20 |
--------------------------------------------------------------------------------
/bin/yaml-sort-checker.php:
--------------------------------------------------------------------------------
1 | setCatchExceptions(false);
30 | $application->add(new CheckCommand());
31 | $application->setDefaultCommand('yaml-check-sort', true);
32 | $application->run();
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Martin Hujer
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/ruleset.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | vendor/
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
16 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
40 |
41 |
42 |
43 | 5
44 |
45 |
46 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mhujer/yaml-sort-checker",
3 | "type": "library",
4 | "description": "YAML sort checker checks if your YML files are properly sorted to prevent merge conflicts",
5 | "keywords": [
6 | "yaml",
7 | "sorter"
8 | ],
9 | "homepage": "https://github.com/mhujer/yaml-sort-checked",
10 | "license": "MIT",
11 | "authors": [
12 | {
13 | "name": "Martin Hujer",
14 | "email": "mhujer@gmail.com",
15 | "homepage": "https://www.martinhujer.cz"
16 | }
17 | ],
18 | "bin": [
19 | "bin/yaml-sort-checker"
20 | ],
21 | "require": {
22 | "php": "~7.3 | ^8.0",
23 | "symfony/console": "~3.4|~4.3|~5.0",
24 | "symfony/yaml": "~3.4|~4.3|~5.0"
25 | },
26 | "require-dev": {
27 | "consistence/coding-standard": "3.10.1",
28 | "php-parallel-lint/php-parallel-lint": "1.2.0",
29 | "phpstan/phpstan": "0.12.57",
30 | "phpunit/phpunit": "9.4.3",
31 | "slevomat/coding-standard": "6.4.1"
32 | },
33 | "autoload": {
34 | "psr-4": {
35 | "Mhujer\\YamlSortChecker\\": [
36 | "src"
37 | ]
38 | },
39 | "classmap": [
40 | "src"
41 | ]
42 | },
43 | "autoload-dev": {
44 | "psr-4": {
45 | "Mhujer\\YamlSortChecker\\": [
46 | "tests"
47 | ]
48 | },
49 | "classmap": [
50 | "tests"
51 | ]
52 | },
53 | "scripts": {
54 | "build": [
55 | "@phplint",
56 | "@phpcs",
57 | "@phpstan",
58 | "@test"
59 | ],
60 | "phplint": "parallel-lint -j 10 --exclude vendor .",
61 | "phpcs": "phpcs --standard=ruleset.xml --extensions=php --encoding=utf-8 --tab-width=4 -sp bin src tests",
62 | "phpstan": "@php vendor/bin/phpstan analyse bin src tests --level 7 --no-progress",
63 | "test": "phpunit"
64 | },
65 | "config": {
66 | "sort-packages": true
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/docs/symfony-config/yaml-sort-checker.yml:
--------------------------------------------------------------------------------
1 | files:
2 | app/config/config.yml:
3 | excludedKeys:
4 | doctrine:
5 | dbal:
6 | - dbname
7 | - port
8 | - user
9 | - password
10 | - charset
11 | - default_table_options
12 | swiftmailer:
13 | - transport
14 | - host
15 | - username
16 | - password
17 | excludedSections:
18 | 0: imports
19 | 1: parameters
20 |
21 | app/config/config_dev.yml:
22 | excludedKeys:
23 | 0: imports
24 | monolog:
25 | handlers:
26 | console:
27 | - type
28 | main:
29 | - type
30 |
31 | app/config/config_prod.yml:
32 | excludedKeys:
33 | monolog:
34 | handlers:
35 | main:
36 | - type
37 | nested:
38 | - type
39 |
40 | app/config/config_test.yml:
41 | excludedKeys:
42 | 0: imports
43 |
44 | app/config/parameters.yml.dist:
45 | excludedKeys:
46 | parameters:
47 | - database_host
48 | - database_port
49 | - database_name
50 | - database_user
51 | - database_password
52 | - mailer_transport
53 | - mailer_host
54 | - mailer_user
55 | - mailer_password
56 |
57 | app/config/routing.yml:
58 | depth: 1
59 |
60 | app/config/routing_dev.yml:
61 | depth: 1
62 |
63 | app/config/security.yml:
64 |
65 | app/config/services.yml:
66 | depth: 2
67 |
68 | yaml-sort-checker.yml:
69 |
--------------------------------------------------------------------------------
/tests/fixture/symfony-config.yml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: parameters.yml }
3 | - { resource: security.yml }
4 | - { resource: services.yml }
5 |
6 | # Put parameters here that don't need to change on each machine where the app is deployed
7 | # http://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
8 | parameters:
9 | locale: en
10 |
11 | framework:
12 | #esi: ~
13 | #translator: { fallbacks: ["%locale%"] }
14 | secret: "%secret%"
15 | router:
16 | resource: "%kernel.root_dir%/config/routing.yml"
17 | strict_requirements: ~
18 | form: ~
19 | csrf_protection: ~
20 | validation: { enable_annotations: true }
21 | #serializer: { enable_annotations: true }
22 | templating:
23 | engines: ['twig']
24 | default_locale: "%locale%"
25 | trusted_hosts: ~
26 | trusted_proxies: ~
27 | session:
28 | # http://symfony.com/doc/current/reference/configuration/framework.html#handler-id
29 | handler_id: session.handler.native_file
30 | save_path: "%kernel.root_dir%/../var/sessions/%kernel.environment%"
31 | fragments: ~
32 | http_method_override: true
33 | assets: ~
34 | php_errors:
35 | log: true
36 |
37 | # Twig Configuration
38 | twig:
39 | debug: "%kernel.debug%"
40 | strict_variables: "%kernel.debug%"
41 |
42 | # Doctrine Configuration
43 | doctrine:
44 | dbal:
45 | driver: pdo_mysql
46 | host: "%database_host%"
47 | port: "%database_port%"
48 | dbname: "%database_name%"
49 | user: "%database_user%"
50 | password: "%database_password%"
51 | charset: UTF8
52 | # if using pdo_sqlite as your database driver:
53 | # 1. add the path in parameters.yml
54 | # e.g. database_path: "%kernel.root_dir%/data/data.db3"
55 | # 2. Uncomment database_path in parameters.yml.dist
56 | # 3. Uncomment next line:
57 | # path: "%database_path%"
58 |
59 | orm:
60 | auto_generate_proxy_classes: "%kernel.debug%"
61 | naming_strategy: doctrine.orm.naming_strategy.underscore
62 | auto_mapping: true
63 |
64 | # Swiftmailer Configuration
65 | swiftmailer:
66 | transport: "%mailer_transport%"
67 | host: "%mailer_host%"
68 | username: "%mailer_user%"
69 | password: "%mailer_password%"
70 | spool: { type: memory }
71 |
--------------------------------------------------------------------------------
/src/CheckCommand.php:
--------------------------------------------------------------------------------
1 | setName('yaml-check-sort');
17 | }
18 |
19 | protected function execute(InputInterface $input, OutputInterface $output): ?int
20 | {
21 | $output->writeln('#### YAML Sort Checker ####');
22 |
23 | $configFilePath = realpath('yaml-sort-checker.yml');
24 | if ($configFilePath === false) {
25 | $output->writeln(sprintf('Config file "%s" not found!', 'yaml-sort-checker.yml'));
26 | exit(1);
27 | }
28 | $output->writeln(sprintf('Using config file "%s"', $configFilePath));
29 |
30 | $configFileContents = file_get_contents($configFilePath);
31 | if ($configFileContents === false) {
32 | throw new \Exception(sprintf('File "%s" could not be loaded', $configFilePath));
33 | }
34 | $config = Yaml::parse($configFileContents);
35 |
36 | if (!array_key_exists('files', $config)) {
37 | $output->writeln('There must be a key "files" in config');
38 | exit(1);
39 | }
40 |
41 | if (count($config['files']) === 0) {
42 | $output->writeln('There must be some files in the config');
43 | exit(1);
44 | }
45 |
46 | $output->writeln('');
47 |
48 | $isOk = true;
49 | $sortChecker = new SortChecker();
50 | foreach ($config['files'] as $filename => $options) {
51 | if (!is_array($options)) {
52 | $options = [];
53 | }
54 |
55 | $depth = array_key_exists('depth', $options) ? $options['depth'] : 999;
56 | $excludedKeys = array_key_exists('excludedKeys', $options) ? $options['excludedKeys'] : [];
57 | $excludedSections = array_key_exists('excludedSections', $options) ? $options['excludedSections'] : [];
58 |
59 | $output->write(sprintf('Checking %s: ', $filename));
60 | if (realpath($filename) === false || !is_readable(realpath($filename))) {
61 | $output->writeln('NOT READABLE!');
62 | exit(1);
63 | }
64 |
65 | $sortCheckResult = $sortChecker->isSorted($filename, $depth, $excludedKeys, $excludedSections);
66 |
67 | if ($sortCheckResult->isOk()) {
68 | $output->writeln('OK');
69 | } else {
70 | $output->writeln('ERROR');
71 | foreach ($sortCheckResult->getMessages() as $message) {
72 | $output->writeln(' ' . $message);
73 | }
74 | $isOk = false;
75 | }
76 | }
77 |
78 | $output->writeln('');
79 | if (!$isOk) {
80 | $output->writeln('Fix the YAMLs or exclude the keys in the config.');
81 | return 1;
82 | } else {
83 | $output->writeln('All YAMLs are properly sorted.');
84 | return 0;
85 | }
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # YAML file sort checker [](https://travis-ci.org/mhujer/yaml-sort-checker)
2 |
3 | [](https://packagist.org/packages/mhujer/yaml-sort-checker) [](https://packagist.org/packages/mhujer/yaml-sort-checker) [](https://packagist.org/packages/mhujer/yaml-sort-checker)
4 |
5 | This library helps you to keep YAML file sorted to prevent unnecessary merge conflicts.
6 |
7 | > Check out the article I've written about the tool: [Keep your YAML files sorted with YAML sort checker](https://blog.martinhujer.cz/yaml-sort-checker/)
8 |
9 | Typical example is when two developers register a new service in `services.yml`. If they both add it to the end, it unevitably will lead to a merge conflict. However, when the services are alphabetically sorted, the probability of merge conflict is much lower (because the added services probably won't clash).
10 |
11 | 
12 |
13 | Usage
14 | ----
15 | 1. Install the latest version with `composer require --dev mhujer/yaml-sort-checker`
16 | 2. Create a configuration file `yaml-sort-checker.yml` in project root with list of the files for checking, see the [example configuration for Symfony app](/docs/symfony-config/yaml-sort-checker.yml).
17 | 3. Run `vendor/bin/yaml-sort-checker` (depends on where you have your Composer bin directory)
18 | 4. Exclude the yaml keys (or even whole sections) you don't want to sort - e.g. it makes more sense to have them unsorted (see the [example configuration](/docs/symfony-config/yaml-sort-checker.yml))
19 |
20 | PHPStorm Integration
21 | ---------------------
22 | Until [WI-35271](https://youtrack.jetbrains.com/issue/WI-35271) is resolved, YAML sort checker can be integrated into PHPStorm by using File Watcher feature.
23 |
24 | 1. Open Settings -> Tools -> File Watchers
25 | 2. Add new
26 | 3. File type: `YAML`
27 | 4. Program: `PATH_TO_YOUR_PROJECT\vendor\bin\yaml-sort-checker.bat`
28 | 5. Open *Other Options* and enter: `$ProjectFileDir$` to *Working directory*
29 | 6. Now, when you are editing YAML files, it will run the checker on every file save and will open the console if there are errors
30 |
31 | Requirements
32 | ------------
33 | Works with PHP 7.2 or higher and Symfony 3.4 or higher.
34 |
35 | Submitting bugs and feature requests
36 | ------------------------------------
37 | Bugs and feature request are tracked on [GitHub](https://github.com/mhujer/yaml-sort-checker/issues)
38 |
39 | Author
40 | ------
41 | [Martin Hujer](https://www.martinhujer.cz)
42 |
43 | Changelog
44 | ----------
45 |
46 | See [CHANGELOG.md](./CHANGELOG.md) for latest changes.
47 |
--------------------------------------------------------------------------------
/src/SortChecker.php:
--------------------------------------------------------------------------------
1 | areDataSorted($data, $excludedKeys, $excludedSections, null, $depth);
34 |
35 | return new SortCheckResult($errors);
36 |
37 | } catch (\Symfony\Component\Yaml\Exception\ParseException $e) {
38 | return new SortCheckResult([
39 | sprintf('Unable to parse the YAML string: %s', $e->getMessage()),
40 | ]);
41 | }
42 | }
43 |
44 | /**
45 | * @param mixed[] $yamlData
46 | * @param mixed[]|string[]|string[][] $excludedKeys
47 | * @param mixed[]|string[]|string[][] $excludedSections
48 | * @param string|null $parent
49 | * @param int $depth
50 | * @return string[] array of error messages
51 | */
52 | private function areDataSorted(
53 | array $yamlData,
54 | array $excludedKeys,
55 | array $excludedSections,
56 | ?string $parent = null,
57 | int $depth
58 | ): array
59 | {
60 | if ($depth === 0) {
61 | return [];
62 | }
63 |
64 | $errors = [];
65 | $lastKey = null;
66 | foreach ($yamlData as $key => $value) {
67 | $isSectionExcluded = false;
68 | if (in_array($key, $excludedSections, true)) {
69 | $isSectionExcluded = true;
70 | }
71 |
72 | if (!$isSectionExcluded && !in_array($key, $excludedKeys, true)) { // isn't excluded
73 | if ($lastKey !== null && is_string($lastKey) && is_string($key)) {
74 | if (strcasecmp($key, $lastKey) < 0) {
75 | if ($parent !== null) {
76 | $printKey = $parent . '.' . $key;
77 | $printLastKey = $parent . '.' . $lastKey;
78 | } else {
79 | $printKey = $key;
80 | $printLastKey = $lastKey;
81 | }
82 | $errors[] = sprintf('"%s" should be before "%s"', $printKey, $printLastKey);
83 | }
84 | }
85 | $lastKey = $key;
86 | }
87 |
88 | $nextExcludedKeys = [];
89 | if (array_key_exists($key, $excludedKeys)) {
90 | $nextExcludedKeys = $excludedKeys[$key];
91 | }
92 |
93 | $nextExcludedSections = [];
94 | if (array_key_exists($key, $excludedSections)) {
95 | $nextExcludedSections = $excludedSections[$key];
96 | }
97 |
98 | if (!$isSectionExcluded && is_array($value)) {
99 | $errors = array_merge(
100 | $errors,
101 | $this->areDataSorted(
102 | $value,
103 | $nextExcludedKeys,
104 | $nextExcludedSections,
105 | ($parent !== null ? $parent . '.' : '') . $key,
106 | $depth - 1
107 | )
108 | );
109 | }
110 | }
111 |
112 | return $errors;
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/tests/SortCheckerTest.php:
--------------------------------------------------------------------------------
1 | isSorted(__DIR__ . '/fixture/ok.yml', 10);
14 |
15 | $this->assertTrue($result->isOk());
16 | $this->assertCount(0, $result->getMessages());
17 | }
18 |
19 | public function testSortedFileWithCustomTag(): void
20 | {
21 | $checker = new SortChecker();
22 | $result = $checker->isSorted(__DIR__ . '/fixture/ok-tagged.yml', 10);
23 |
24 | $this->assertTrue($result->isOk());
25 | $this->assertCount(0, $result->getMessages());
26 | }
27 |
28 | public function testInvalidYamlIsInvalid(): void
29 | {
30 | $checker = new SortChecker();
31 | $result = $checker->isSorted(__DIR__ . '/fixture/invalid-yaml.yml', 1);
32 |
33 | $this->assertFalse($result->isOk());
34 | $this->assertCount(1, $result->getMessages());
35 | $this->assertStringStartsWith('Unable to parse the YAML string', $result->getMessages()[0]);
36 | }
37 |
38 | public function testInvalidSortInFirstLevel(): void
39 | {
40 | $checker = new SortChecker();
41 | $result = $checker->isSorted(__DIR__ . '/fixture/first-level.yml', 1);
42 |
43 | $this->assertFalse($result->isOk());
44 | $this->assertCount(1, $result->getMessages());
45 | $this->assertSame('"bar" should be before "foo"', $result->getMessages()[0]);
46 | }
47 |
48 | public function testInvalidSortInFirstLevelWithExcludeKeys(): void
49 | {
50 | $checker = new SortChecker();
51 | $result = $checker->isSorted(
52 | __DIR__ . '/fixture/first-level.yml',
53 | 1,
54 | [
55 | 'bar',
56 | ]
57 | );
58 | $this->assertTrue($result->isOk());
59 | }
60 |
61 | public function testInvalidSortInSecondLevel(): void
62 | {
63 | $checker = new SortChecker();
64 | $result = $checker->isSorted(__DIR__ . '/fixture/second-level.yml', 2);
65 |
66 | $this->assertFalse($result->isOk());
67 | $this->assertCount(1, $result->getMessages());
68 | $this->assertSame('"foo.car" should be before "foo.dar"', $result->getMessages()[0]);
69 | }
70 |
71 | public function testInvalidSortInSecondLevelWithExcludeKeys(): void
72 | {
73 | $checker = new SortChecker();
74 | $result = $checker->isSorted(
75 | __DIR__ . '/fixture/second-level.yml',
76 | 2,
77 | [
78 | 'foo' => [
79 | 'car',
80 | ],
81 | ]
82 | );
83 |
84 | $this->assertTrue($result->isOk());
85 | }
86 |
87 | public function testInvalidSortInFirstAndSecondLevel(): void
88 | {
89 | $checker = new SortChecker();
90 | $result = $checker->isSorted(__DIR__ . '/fixture/first-and-second-level.yml', 2);
91 |
92 | $this->assertFalse($result->isOk());
93 | $this->assertCount(2, $result->getMessages());
94 | $this->assertSame('"foo" should be before "zoo"', $result->getMessages()[0]);
95 | $this->assertSame('"foo.car" should be before "foo.dar"', $result->getMessages()[1]);
96 | }
97 |
98 | public function testInvalidSortInFirstSecondAndThirdLevel(): void
99 | {
100 | $checker = new SortChecker();
101 | $result = $checker->isSorted(__DIR__ . '/fixture/first-second-and-third-level.yml', 3);
102 |
103 | $this->assertFalse($result->isOk());
104 | $this->assertCount(3, $result->getMessages());
105 | $this->assertSame('"foo" should be before "zoo"', $result->getMessages()[0]);
106 | $this->assertSame('"foo.car" should be before "foo.dar"', $result->getMessages()[1]);
107 | $this->assertSame('"foo.car.c" should be before "foo.car.d"', $result->getMessages()[2]);
108 | }
109 |
110 | public function testExcludedFirstAndSecondLevelDoesNotPreventCheckingOfThirdLevel(): void
111 | {
112 | $checker = new SortChecker();
113 | $result = $checker->isSorted(
114 | __DIR__ . '/fixture/first-second-and-third-level.yml',
115 | 3,
116 | [
117 | 0 => 'foo',
118 | 'foo' => [
119 | 'dar',
120 | ],
121 | ]
122 | );
123 |
124 | $this->assertFalse($result->isOk());
125 | $this->assertCount(1, $result->getMessages());
126 | $this->assertSame('"foo.car.c" should be before "foo.car.d"', $result->getMessages()[0]);
127 | }
128 |
129 | public function testInvalidSortWithExcludeFirstLevelSection(): void
130 | {
131 | $checker = new SortChecker();
132 | $result = $checker->isSorted(
133 | __DIR__ . '/fixture/third-level.yml',
134 | 999,
135 | [],
136 | ['foo']
137 | );
138 | $this->assertTrue($result->isOk());
139 | }
140 |
141 | public function testInvalidSortWithExcludeSecondLevelSection(): void
142 | {
143 | $checker = new SortChecker();
144 | $result = $checker->isSorted(
145 | __DIR__ . '/fixture/third-level.yml',
146 | 999,
147 | [],
148 | ['foo' => ['car']]
149 | );
150 | $this->assertSame([], $result->getMessages());
151 | $this->assertTrue($result->isOk());
152 | }
153 |
154 | public function testSymfonyConfig(): void
155 | {
156 | $checker = new SortChecker();
157 | $result = $checker->isSorted(__DIR__ . '/fixture/symfony-config.yml', 5);
158 |
159 | $this->assertFalse($result->isOk());
160 | $this->assertCount(16, $result->getMessages());
161 | $this->assertSame(
162 | [
163 | '"framework" should be before "parameters"',
164 | '"framework.router" should be before "framework.secret"',
165 | '"framework.form" should be before "framework.router"',
166 | '"framework.csrf_protection" should be before "framework.form"',
167 | '"framework.templating" should be before "framework.validation"',
168 | '"framework.default_locale" should be before "framework.templating"',
169 | '"framework.session" should be before "framework.trusted_proxies"',
170 | '"framework.fragments" should be before "framework.session"',
171 | '"framework.assets" should be before "framework.http_method_override"',
172 | '"doctrine" should be before "twig"',
173 | '"doctrine.dbal.dbname" should be before "doctrine.dbal.port"',
174 | '"doctrine.dbal.password" should be before "doctrine.dbal.user"',
175 | '"doctrine.dbal.charset" should be before "doctrine.dbal.password"',
176 | '"doctrine.orm.auto_mapping" should be before "doctrine.orm.naming_strategy"',
177 | '"swiftmailer.host" should be before "swiftmailer.transport"',
178 | '"swiftmailer.password" should be before "swiftmailer.username"',
179 | ],
180 | $result->getMessages()
181 | );
182 | }
183 |
184 | public function testSymfonyConfigWithExcludedKeys(): void
185 | {
186 | $checker = new SortChecker();
187 | $result = $checker->isSorted(
188 | __DIR__ . '/fixture/symfony-config.yml',
189 | 5,
190 | [
191 | 0 => 'imports',
192 | 1 => 'parameters',
193 | 'doctrine' => [
194 | 'dbal' => [
195 | 'dbname',
196 | 'charset',
197 | 'port',
198 | 'user',
199 | ],
200 | ],
201 | 'swiftmailer' => [
202 | 'host',
203 | 'transport',
204 | 'username',
205 | 'password',
206 | ],
207 | ]
208 | );
209 |
210 | $this->assertFalse($result->isOk());
211 | $this->assertCount(10, $result->getMessages());
212 | $this->assertSame(
213 | [
214 | '"framework.router" should be before "framework.secret"',
215 | '"framework.form" should be before "framework.router"',
216 | '"framework.csrf_protection" should be before "framework.form"',
217 | '"framework.templating" should be before "framework.validation"',
218 | '"framework.default_locale" should be before "framework.templating"',
219 | '"framework.session" should be before "framework.trusted_proxies"',
220 | '"framework.fragments" should be before "framework.session"',
221 | '"framework.assets" should be before "framework.http_method_override"',
222 | '"doctrine" should be before "twig"',
223 | '"doctrine.orm.auto_mapping" should be before "doctrine.orm.naming_strategy"',
224 | ],
225 | $result->getMessages()
226 | );
227 | }
228 |
229 | public function testSymfonyConfigWithExcludedSections(): void
230 | {
231 | $checker = new SortChecker();
232 | $result = $checker->isSorted(
233 | __DIR__ . '/fixture/symfony-config.yml',
234 | 999,
235 | [],
236 | [
237 | 'doctrine' => [
238 | 'dbal',
239 | ],
240 | 0 => 'framework',
241 | ]
242 | );
243 |
244 | $this->assertFalse($result->isOk());
245 | $this->assertSame(
246 | [
247 | '"doctrine" should be before "twig"',
248 | '"doctrine.orm.auto_mapping" should be before "doctrine.orm.naming_strategy"',
249 | '"swiftmailer.host" should be before "swiftmailer.transport"',
250 | '"swiftmailer.password" should be before "swiftmailer.username"',
251 | ],
252 | $result->getMessages()
253 | );
254 | }
255 |
256 | }
257 |
--------------------------------------------------------------------------------