diff --git a/README.md b/README.md index d3274a7..10fdc73 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,8 @@ Usage "merge-extra": false, "merge-extra-deep": false, "merge-replace": true, - "merge-scripts": false + "merge-scripts": false, + "merge-scripts-deep": false } } } @@ -197,6 +198,14 @@ the master config wins over the version found in any imported config). If and the last key found will win (e.g. the key in the master config is replaced by the key in the imported config). +if `"merge-scripts-deep": true` (required `"merge-scripts": true`), the scripts will be merged, not replaced, with +the first option found, or the last one, depending on the settings, as +with only `"merge-scripts": true`. +For example, _root: script => 1, imported: script => 2, the output will be script => [1, 2]_, +but with the same values, at the moment, they will be repeated +_root: script => 1, imported: script => 1, output: script => [1, 1]_ + + Note: [custom commands][] added by merged configuration will work when invoked as `composer run-script my-cool-command` but will not be available using the normal `composer my-cool-command` shortcut. diff --git a/src/ExtraPackage.php b/src/ExtraPackage.php index 2471cb0..5fd15c7 100644 --- a/src/ExtraPackage.php +++ b/src/ExtraPackage.php @@ -544,15 +544,20 @@ public function mergeScripts(RootPackageInterface $root, PluginState $state) $rootScripts = $root->getScripts(); $unwrapped = self::unwrapIfNeeded($root, 'setScripts'); + if ($state->shouldMergeScriptsDeep()) { + $unwrapped->setScripts(array_merge_recursive($rootScripts, $scripts)); + return; + } + if ($state->replaceDuplicateLinks()) { $unwrapped->setScripts( array_merge($rootScripts, $scripts) ); - } else { - $unwrapped->setScripts( - array_merge($scripts, $rootScripts) - ); + return; } + $unwrapped->setScripts( + array_merge($scripts, $rootScripts) + ); } /** diff --git a/src/PluginState.php b/src/PluginState.php index 1987883..5cef5fd 100644 --- a/src/PluginState.php +++ b/src/PluginState.php @@ -112,6 +112,12 @@ class PluginState */ protected $mergeScripts = false; + /** + * @var bool $mergeScriptsDeep + */ + protected $mergeScriptsDeep = false; + + /** * @var bool $firstInstall */ @@ -169,6 +175,7 @@ public function loadSettings() 'merge-extra-deep' => false, 'merge-replace' => true, 'merge-scripts' => false, + 'merge-scripts-deep' => false, ], $extra['merge-plugin'] ?? [] ); @@ -185,6 +192,7 @@ public function loadSettings() $this->mergeExtraDeep = (bool)$config['merge-extra-deep']; $this->mergeReplace = (bool)$config['merge-replace']; $this->mergeScripts = (bool)$config['merge-scripts']; + $this->mergeScriptsDeep = (bool)$config['merge-scripts-deep']; } /** @@ -418,5 +426,17 @@ public function shouldMergeScripts() { return $this->mergeScripts; } + + /** + * Should the scripts section be deep merged? + * + * By default, the scripts section is not merged. + * + * @return bool + */ + public function shouldMergeScriptsDeep() + { + return $this->mergeScriptsDeep; + } } // vim:sw=4:ts=4:sts=4:et: diff --git a/tests/phpunit/MergePluginTest.php b/tests/phpunit/MergePluginTest.php index 1eb4d5f..3aa91b6 100644 --- a/tests/phpunit/MergePluginTest.php +++ b/tests/phpunit/MergePluginTest.php @@ -1192,6 +1192,41 @@ function ($args) use ($that) { $this->triggerPlugin($root->reveal(), $dir); } + public function testMergeScriptsDeep() + { + $that = $this; + $dir = $this->fixtureDir(__FUNCTION__); + + $root = $this->rootFromJson("{$dir}/composer.json"); + + + $root->setScripts(Argument::type('array'))->will( + function ($args) use ($that) { + $scripts = $args[0]; + var_dump($scripts); + $that->assertCount(4, $scripts); + $that->assertArrayHasKey('script2', $scripts); + $that->assertArrayHasKey('script3', $scripts); + $that->assertEquals(["echo 'script2-root'", "echo 'script2-1'"], $scripts['script2']); + $that->assertCount(3, $scripts['script3']); + $that->assertEquals( + ["echo 'script3-root'", "echo 'script3-1'", "echo 'script3-2'"], + $scripts['script3'] + ); + $that->assertCount(2, $scripts['script4']); + $that->assertEquals(["echo 'script4'", "echo 'script4'"], $scripts['script4']); + } + )->shouldBeCalled(); + + $root->getRepositories()->shouldNotBeCalled(); + $root->getConflicts()->shouldNotBeCalled(); + $root->getReplaces()->shouldNotBeCalled(); + $root->getProvides()->shouldNotBeCalled(); + $root->getSuggests()->shouldNotBeCalled(); + + $this->triggerPlugin($root->reveal(), $dir); + } + /** * @dataProvider provideOnPostPackageInstall * @param string $package Package installed diff --git a/tests/phpunit/fixtures/testMergeScriptsDeep/composer.json b/tests/phpunit/fixtures/testMergeScriptsDeep/composer.json new file mode 100644 index 0000000..ef73d7a --- /dev/null +++ b/tests/phpunit/fixtures/testMergeScriptsDeep/composer.json @@ -0,0 +1,18 @@ +{ + "extra": { + "merge-plugin": { + "merge-scripts": true, + "merge-scripts-deep": true, + "include": [ + "composer.local.json" + ] + } + }, + "scripts": { + "script2": "echo 'script2-root'", + "script3": [ + "echo 'script3-root'" + ], + "script4": "echo 'script4'" + } +} \ No newline at end of file diff --git a/tests/phpunit/fixtures/testMergeScriptsDeep/composer.local.json b/tests/phpunit/fixtures/testMergeScriptsDeep/composer.local.json new file mode 100644 index 0000000..9c75f8b --- /dev/null +++ b/tests/phpunit/fixtures/testMergeScriptsDeep/composer.local.json @@ -0,0 +1,14 @@ +{ + "scripts": { + + "script1": "echo 'script1-1'", + "script2": "echo 'script2-1'", + "script3": [ + "echo 'script3-1'", + "echo 'script3-2'" + ], + "script4": [ + "echo 'script4'" + ] + } +} \ No newline at end of file