Giter Site home page Giter Site logo

composer-merge-plugin's Introduction

Latest Stable Version License Build Status Code Coverage

Composer Merge Plugin

Merge multiple composer.json files at Composer runtime.

Composer Merge Plugin is intended to allow easier dependency management for applications which ship a composer.json file and expect some deployments to install additional Composer managed libraries. It does this by allowing the application's top level composer.json file to provide a list of optional additional configuration files. When Composer is run it will parse these files and merge their configuration settings into the base configuration. This combined configuration will then be used when downloading additional libraries and generating the autoloader.

Composer Merge Plugin was created to help with installation of MediaWiki which has core library requirements as well as optional libraries and extensions which may be managed via Composer.

Installation

Composer Merge Plugin 1.4.x (and older) requires Composer 1.x.

Composer Merge Plugin 2.0.x (and newer) is compatible with both Composer 2.x and 1.x.

$ composer require wikimedia/composer-merge-plugin

Upgrading from Composer 1 to 2

If you are already using Composer Merge Plugin 1.4 (or older) and you are updating the plugin to 2.0 (or newer), it is recommended that you update the plugin first using Composer 1.

If you update the incompatible plugin using Composer 2, the plugin will be ignored:

The "wikimedia/composer-merge-plugin" plugin was skipped because it requires a Plugin API version ("^1.0") that does not match your Composer installation ("2.0.0"). You may need to run composer update with the "--no-plugins" option.

Consequently, Composer will be unaware of the merged dependencies and will remove them requiring you to run composer update again to reinstall merged dependencies.

Usage

{
    "require": {
        "wikimedia/composer-merge-plugin": "dev-master"
    },
    "extra": {
        "merge-plugin": {
            "include": [
                "composer.local.json",
                "extensions/*/composer.json"
            ],
            "require": [
                "submodule/composer.json"
            ],
            "recurse": true,
            "replace": false,
            "ignore-duplicates": false,
            "merge-dev": true,
            "merge-extra": false,
            "merge-extra-deep": false,
            "merge-replace": true,
            "merge-scripts": false
        }
    }
}

Updating sub-levels composer.json files

In order for Composer Merge Plugin to install dependencies from updated or newly created sub-level composer.json files in your project you need to run the command:

$ composer update

This will instruct Composer to recalculate the file hash for the top-level composer.json thus triggering Composer Merge Plugin to look for the sub-level configuration files and update your dependencies.

Plugin configuration

The plugin reads its configuration from the merge-plugin section of your composer.json's extra section. An include setting is required to tell Composer Merge Plugin which file(s) to merge.

include

The include setting can specify either a single value or an array of values. Each value is treated as a PHP glob() pattern identifying additional composer.json style configuration files to merge into the root package configuration for the current Composer execution.

The following sections of the found configuration files will be merged into the Composer root package configuration as though they were directly included in the top-level composer.json file:

require

The require setting is identical to include except when a pattern fails to match at least one file then it will cause an error.

recurse

By default the merge plugin is recursive; if an included file has a merge-plugin section it will also be processed. This functionality can be disabled by adding a "recurse": false setting.

replace

By default, Composer's conflict resolution engine is used to determine which version of a package should be installed when multiple files specify the same package. A "replace": true setting can be provided to change to a "last version specified wins" conflict resolution strategy. In this mode, duplicate package declarations found in merged files will overwrite the declarations made by earlier files. Files are loaded in the order specified by the include setting with globbed files being processed in alphabetical order.

ignore-duplicates

By default, Composer's conflict resolution engine is used to determine which version of a package should be installed when multiple files specify the same package. An "ignore-duplicates": true setting can be provided to change to a "first version specified wins" conflict resolution strategy. In this mode, duplicate package declarations found in merged files will be ignored in favor of the declarations made by earlier files. Files are loaded in the order specified by the include setting with globbed files being processed in alphabetical order.

Note: "replace": true and "ignore-duplicates": true modes are mutually exclusive. If both are set, "ignore-duplicates": true will be used.

merge-dev

By default, autoload-dev and require-dev sections of included files are merged. A "merge-dev": false setting will disable this behavior.

merge-extra

A "merge-extra": true setting enables the merging the contents of the extra section of included files as well. The normal merge mode for the extra section is to accept the first version of any key found (e.g. a key in the master config wins over the version found in any imported config). If replace mode is active (see above) then this behavior changes 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-extra-deep": true is specified then, the sections are merged similar to array_merge_recursive() - however duplicate string array keys are replaced instead of merged, while numeric array keys are merged as usual. The usefulness of merging the extra section will vary depending on the Composer plugins being used and the order in which they are processed by Composer.

Note that merge-plugin sections are excluded from the merge process, but are always processed by the plugin unless recursion is disabled.

merge-replace

By default, the replace section of included files are merged. A "merge-replace": false setting will disable this behavior.

merge-scripts

A "merge-scripts": true setting enables merging the contents of the scripts section of included files as well. The normal merge mode for the scripts section is to accept the first version of any key found (e.g. a key in the master config wins over the version found in any imported config). If replace mode is active (see above) then this behavior changes and the last key found will win (e.g. the key in the master config is replaced by the key in the imported config).

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.

Running tests

$ composer install
$ composer test

Contributing

Bug, feature requests and other issues should be reported to the GitHub project. We accept code and documentation contributions via Pull Requests on GitHub as well.

  • PSR-2 Coding Standard is used by the project. The included test configuration uses PHP_CodeSniffer to validate the conventions.
  • Tests are encouraged. Our test coverage isn't perfect but we'd like it to get better rather than worse, so please try to include tests with your changes.
  • Keep the documentation up to date. Make sure README.md and other relevant documentation is kept up to date with your changes.
  • One pull request per feature. Try to keep your changes focused on solving a single problem. This will make it easier for us to review the change and easier for you to make sure you have updated the necessary tests and documentation.

License

Composer Merge plugin is licensed under the MIT license. See the LICENSE file for more details.


composer-merge-plugin's People

Contributors

arcanedev-maroc avatar bd808 avatar far-blue avatar furgas avatar grasmash avatar jeroendedauw avatar jiripudil avatar krinkle avatar legoktm avatar lionsad avatar mcaskill avatar mjauvin avatar redgluten avatar reedy avatar remicollet avatar rhofland avatar theofidry avatar thewilkybarkid avatar tstarling avatar webflo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

composer-merge-plugin's Issues

This is not a "at runtime" plugin.

If I understand correctly, the plugin tries to load the "include" composer.json files at build time (composer update and composer install). If the composer.json file does not exist during build time or the dependencies are not initialized, the autoloader generation will fail.

IMHO, this is not a runtime plugin. A runtime plugin would not care about the non-existing composer.json file during build time. It would load the composer.json file at runtime and load dependencies when they are needed.

Maybe it's me. Am I doing something wrong?

composer update --dry-run

If I run composer update --dry-run to find out if there's any newer versions available, it appears to not merge in the other composer.json files, so lists all dependencies included there as being removed. This doesn't happen when running composer update, which does correctly update all of them.

Have later configs replace earlier ones

When merging multiple config files it would be very useful to be able to replace an earlier definition with a later one - for example, a stable config with a definition for a stable package being overridden in a dev environment by a dev or beta version of the same package. The current merge implementation identifies the duplicates but then relies on Composer's Solver to find a compatible solution. I suggest a flag to change this with a 'replace' behaviour with 'last defined wins'.

Incompatibility with some plugins (processing merge after?)

Hello

The merge process of the composer-merge-plugin is probably happening after some plugins, meaning these don't get the merged json from merge-plugin.

Detected situations:

I did some research and posted on the aforementioned issues.

Is this supposed to be true recursion?

I was trying to include another file with different options, but I saw that the new extra section is ignored and only the includes and requires are taken into account.

However it would be possible (albeit a little complex) to fix this.

Suggested resolution

  • Either take patch from below and allow to specify within each included file new options, e.g. to stop recursion, etc. This is is the most flexible version.
  • Clearly state in README that recursion does only support includes / requires.

Here is the kinda patch:

diff --git a/src/Merge/ExtraPackage.php b/src/Merge/ExtraPackage.php
index e5e9c85..8859416 100644
--- a/src/Merge/ExtraPackage.php
+++ b/src/Merge/ExtraPackage.php
@@ -101,6 +101,18 @@ class ExtraPackage
     }

     /**
+     * Get extra data.
+     *
+     * @return array
+     */
+    public function getExtra()
+    {
+        return isset($this->json['extra']) ?
+            $this->json['extra'] : array();
+    }
+
+
+    /**
      * Read the contents of a composer.json style file into an array.
      *
      * The package contents are fixed up to be usable to create a Package
diff --git a/src/Merge/PluginState.php b/src/Merge/PluginState.php
index 3ff2fd8..24c59c6 100644
--- a/src/Merge/PluginState.php
+++ b/src/Merge/PluginState.php
@@ -123,9 +123,11 @@ class PluginState
     /**
      * Load plugin settings
      */
-    public function loadSettings()
+    public function loadSettings(array $extra = NULL)
     {
-        $extra = $this->composer->getPackage()->getExtra();
+        if (!isset($extra)) {
+            $extra = $this->composer->getPackage()->getExtra();
+        }
         $config = array_merge(
             array(
                 'include' => array(),
diff --git a/src/MergePlugin.php b/src/MergePlugin.php
index ea41d41..beebe54 100644
--- a/src/MergePlugin.php
+++ b/src/MergePlugin.php
@@ -208,8 +208,12 @@ class MergePlugin implements PluginInterface, EventSubscriberInterface
         $package->mergeInto($root, $this->state);

         if ($this->state->recurseIncludes()) {
+            $oldState = $this->state;
+            $this->state = clone $this->state;
+            $this->state->loadSettings($package->getExtra());
             $this->mergeFiles($package->getIncludes(), false);
             $this->mergeFiles($package->getRequires(), true);
+            $this->state = $oldState;
         }
     }

diff --git a/tests/phpunit/MergePluginTest.php b/tests/phpunit/MergePluginTest.php
index 84f4ac1..8acb67e 100644
--- a/tests/phpunit/MergePluginTest.php
+++ b/tests/phpunit/MergePluginTest.php
@@ -649,6 +649,8 @@ class MergePluginTest extends \PHPUnit_Framework_TestCase
         $root->setExtra(Argument::type('array'))->will(
             function ($args) use ($that) {
                 $extra = $args[0];
+                $this->getExtra()->willReturn($extra);
                 $that->assertEquals(3, count($extra));
                 $that->assertArrayHasKey('merge-plugin', $extra);
                 $that->assertEquals(4, count($extra['merge-plugin']));
diff --git a/tests/phpunit/fixtures/testMergeDeep/composer.local.json b/tests/phpunit/fixtures/testMergeDeep/composer.local.json
index 2868fc3..13f996d 100644
--- a/tests/phpunit/fixtures/testMergeDeep/composer.local.json
+++ b/tests/phpunit/fixtures/testMergeDeep/composer.local.json
@@ -1,5 +1,11 @@
 {
     "extra": {
+        "merge-plugin": {
+            "merge-extra": true,
+            "merge-deep": true,
+            "replace": false,
+            "include": ["composer.base.json"]
+        },
         "patches": {
             "wikimedia/composer-merge-plugin": {
                 "Allow merging of sections in a deep way": "patches/add-merge-deep-option.diff"

It is based on my recent PR, so won't apply like that, so I am merely putting this here for discussion and not as a PR.

Warning requires composer-plugin-api 1.0.0

"composer update" gives 'The "wikimedia/composer-merge-plugin" plugin requires composer-plugin-api 1.0.0, this WILL break in the future and it should be fixed ASAP (require ^1.0 for example)'. Is this an issue?

doesn't work

hey guys. i have this part of code

...... 
"require": {
        "php": ">=5.5.9",
        "laravel/framework": "5.2.*",
        "pingpong/modules": "~2.1",
        "wikimedia/composer-merge-plugin": "^1.3"
    },
    "extra": {
        "merge-plugin": {
            "require": [
                "modules/*/composer.json"
            ]
        }
    },
    "require-dev": {
        "fzaninotto/faker": "~1.4",
        "mockery/mockery": "0.9.*",
        "phpunit/phpunit": "~4.0",
        "symfony/css-selector": "2.8.*|3.0.*",
        "symfony/dom-crawler": "2.8.*|3.0.*",
        "barryvdh/laravel-debugbar": "^2.1"
    },
    "autoload": {
        "classmap": [
            "database"
        ],
        "psr-4": {
            "App\\": "app/",
            "Modules\\": "modules/"
        }
    },
.......

bu it doesn't install my dependencies from the composer.json files situated in modules/*.
any idea?

thanks!

Merged VCS repositories aren't installed

I've got a project with a main composer.json and a merged composer.json which I'm trying to use to install a private git project.

With the repository and require config in the merged JSON file the project isn't installed with composer giving a 'package ... could not be found in any version' error.

Moving the repository and require to the main composer.json files results in the package being installed.

A package which is listed on packagist (doesn't require a repository entry in the composer config) installs ok from the merged file.

The installed composer-merge-plugin is at 361e098

Allow included files to include other files

Discussion from https://gerrit.wikimedia.org/r/#/c/182323/:

"extensions/*/composer.json" can also be added to composer.local.json, right?

With version 0.5.0 of the merge plugin, no. At the moment the plugin will only take configuration directives from the top level composer.json file.

Initially I thought that it would be important for the root package maintainer to be able to completely control which globs were scanned for additional includes. After seeing some discussion on the patch to include support in MediaWiki and further reflection, I'm coming around to the idea of nested includes under the deployer's control.

I think there are a few details to work out before diving into implementation:

  • I'm not sure if recursion is needed or if it would be sufficient for only includes specified by first level includes to be processed. Whether this would make implementation easier one way or another remains to be seen.
  • It may be useful to add an additional configuration option that allows this feature to be turned on or off by the root package manager. I'm thinking something like extra.merge-plugin.recurse = true. If this option is created, it should probably be available at each level where recursive includes could be processed.
  • If controlled by a configuration flag, should the feature default to being enabled or disabled?
  • If recursive includes are allowed how hard should we work to avoid loops? Would it be reasonable just to stop and emit an error if more than N files are processed?

@Nikerabbit do you have thoughts on this topic?

Invalid argument supplied for foreach()

Exception trace:
 () at /Users/bd808/projects/wmf/vagrant/mediawiki/vendor/wikimedia/composer-merge-plugin/src/MergePlugin.php:215
 Composer\Util\ErrorHandler::handle() at /Users/bd808/projects/wmf/vagrant/mediawiki/vendor/wikimedia/composer-merge-plugin/src/MergePlugin.php:215
 Wikimedia\Composer\MergePlugin->onDependencySolve() at n/a:n/a
 call_user_func() at phar:///Users/bd808/bin/composer.phar/src/Composer/EventDispatcher/EventDispatcher.php:159
 Composer\EventDispatcher\EventDispatcher->doDispatch() at phar:///Users/bd808/bin/composer.phar/src/Composer/EventDispatcher/EventDispatcher.php:138
 Composer\EventDispatcher\EventDispatcher->dispatchInstallerEvent() at phar:///Users/bd808/bin/composer.phar/src/Composer/Installer.php:497
 Composer\Installer->doInstall() at phar:///Users/bd808/bin/composer.phar/src/Composer/Installer.php:224
 Composer\Installer->run() at phar:///Users/bd808/bin/composer.phar/src/Composer/Command/UpdateCommand.php:134
 Composer\Command\UpdateCommand->execute() at phar:///Users/bd808/bin/composer.phar/vendor/symfony/console/Symfony/Component/Console/Command/Command.php:252
 Symfony\Component\Console\Command\Command->run() at phar:///Users/bd808/bin/composer.phar/vendor/symfony/console/Symfony/Component/Console/Application.php:874
 Symfony\Component\Console\Application->doRunCommand() at phar:///Users/bd808/bin/composer.phar/vendor/symfony/console/Symfony/Component/Console/Application.php:195
 Symfony\Component\Console\Application->doRun() at phar:///Users/bd808/bin/composer.phar/src/Composer/Console/Application.php:146
 Composer\Console\Application->doRun() at phar:///Users/bd808/bin/composer.phar/vendor/symfony/console/Symfony/Component/Console/Application.php:126
 Symfony\Component\Console\Application->run() at phar:///Users/bd808/bin/composer.phar/src/Composer/Console/Application.php:83
 Composer\Console\Application->run() at phar:///Users/bd808/bin/composer.phar/bin/composer:43
 require() at /Users/bd808/bin/composer.phar:25

merge-plugin doesn't process extra.merge-plugin sections from packages required by the project

I'm trying to create a package (a framework) that, when installed, requires this plugin and configures it to include composer.json files from several directories contained inside that same package.
This would allow me to split package requirements between several "modules" inside that package, instead of creating one single, monolithic, big require section on that package's composer.json.
Furthermore, I do not want that configuration to be present on the main project's root composer.json, as the user of my package (framework) should not have to know about those internal details, nor pollute his project's composer.json with irrelevant info. All he/she should have to do is to require the package, as usually.
The problem is, if I configure this:

"merge-plugin": {
  "include": [
    "private/packages/selenia/framework/subsystems/*/composer.json"
  ],
  "recurse": true,
  "replace": false,
  "merge-extra": true
}

on the project's root composer.json, it works, but if I configure it inside the package (which requires this plugin), it does not.
I also tried changing the "include" pattern to be relative to the package's root folder, but to no avail.
It seems this plugin only processes extra.merge-plugin sections of composer.json files that are included from the root composer.json. If a package defines its own extra.merge-plugin section, it won't work.
Is this so?
If it is, could this feature be implemented?

post-install step does not rebuild optimized composer autoloader

composer.json:

{
    "require": {
        "wikimedia/composer-merge-plugin": "1.2.0",
        "psr/log": "1.0.0"
    },
    "config": {
        "classmap-authoritative": true,
        "prepend-autoloader": false,
        "optimize-autoloader": true
    },
    "extra": {
        "merge-plugin": {
            "include": [
                "composer.local.json"
            ]
        }
    }
}

composer.local.json

{
    "require": {
        "zordius/lightncandy": "0.21"
    }
}

Run composer install. Look at vendor/composer/autoload_classmap.php and see that the Psr\Log* entries are not there. This becomes an issue when the "classmap-authoritative" option is used because it does not fallback to the psr0 or psr4 autoloader.

Does include respect lock file?

   "extra": {
        "merge-plugin": {
            "include": [
                "acme/composer.json"
            ]
        }

will it pick up the lock file from acme/composer.lock?

Option to not merge require-dev sections

For MediaWiki extensions, "require" contains the dependencies that should be merged into the main MediaWiki core vendor bundle, while "require-dev" are for the local repository and not meant to be merged/used by MediaWiki. It becomes problematic when different extensions have incompatible development dependency versions.

IRC discussion

Not all merged sections are mentioned on the readme

On the readme you say:

The "require", "require-dev", "repositories" and "suggest" sections of the found configuration files will be merged into the root package configuration

You also mention the capability of merging the extra section.

But, in reality, more sections are being merged, as one can see on the plugin's source code.
So you should also mention these sections (correct me if I'm wrong):

autoload, autoload-dev, minimum-stability, replaces, provides, suggests

Mentioning those on the documentation is very important. I was considering reporting an issue requesting that you add the capability to merge autoload sections (as that is a very useful and needed feature) before I noticed that the feature was already implemented and working well! I even considered abandoning the idea of using this plugin on my framework because I thought that crucial capability was missing (which would make the plugin useless to me).

Require section not merged when using branch alias

Related to #26 and #39

The patch has fixed fatal error, but merge still doesn't work properly. Dependencies from the included files are not loaded by composer.

To reproduce:

  • Create empty git repository: git init
  • Create these two files in the same folder:

composer.json

{
    "require": {
        "wikimedia/composer-merge-plugin": "dev-master"
    },
    "extra": {
        "merge-plugin": {
            "include": [
                "composer.local.json"
            ]
        },
        "branch-alias": {
            "dev-master": "8.0.x-dev"
        }
    }
}

composer.local.json

{
    "require": {
        "psr/log": "~1.0"
    }
}
  • Add and commit:
git add -A
git commit -m "test"
  • Run composer: composer update. Output:
$ composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
  - Installing wikimedia/composer-merge-plugin (dev-master d3d9500)
    Cloning d3d9500b937b0cd2528fc597f8674759ea0adc67

Writing lock file
Generating autoload files
Loading composer repositories with package information
Updating dependencies (including require-dev)
Writing lock file
Generating autoload files

Note, "psr/log" package is not installed.

Now edit composer.json, remove "branch-alias" section and run composer again - this time "psr/log" IS installed.

If you restore branch alias in composer.json and run composer again, "psr/log" will be removed.

Tests failing due to Symfony deprecation

[km@km-tp composer-merge-plugin]$ composer test
PHP Fatal error:  Uncaught exception 'ErrorException' with message '"Symfony\Component\Console\Helper\DialogHelper" is deprecated since version 2.5 and will be removed in 3.0. Use "Symfony\Component\Console\Helper\QuestionHelper" instead.' in /home/km/projects/composer-merge-plugin/vendor/symfony/console/Helper/DialogHelper.php:34
Stack trace:
#0 [internal function]: Composer\Util\ErrorHandler::handle(16384, '"Symfony\\Compon...', '/home/km/projec...', 34, Array)
#1 /home/km/projects/composer-merge-plugin/vendor/symfony/console/Helper/DialogHelper.php(34): trigger_error('"Symfony\\Compon...', 16384)
#2 /home/km/projects/composer-merge-plugin/vendor/composer/composer/src/Composer/Console/Application.php(331): Symfony\Component\Console\Helper\DialogHelper->__construct()
#3 /home/km/projects/composer-merge-plugin/vendor/symfony/console/Application.php(88): Composer\Console\Application->getDefaultHelperSet()
#4 /home/km/projects/composer-merge-plugin/vendor/composer/composer/src/Composer/Console/Application.php(70): Symfony\Compon in /home/km/projects/composer-merge-plugin/vendor/symfony/console/Helper/DialogHelper.php on line 34

Merge the extras section

We needed to be able to merge the extras section so I've updated the code (PR #48). It will only merge non-conflicting top-level keys and it ignores the merge-plugin extras key as that's handled already.

"The requested package *** could not be found." when require-dev has duplicate entries

Consider the following scenario:
You have a MediaWiki wiki with the SyntaxHighlight_GeSHi extension installed. Both, MediaWiki and SyntaxHighlight_GeSHi uses composer to install additional dependencies, dev-requirements and libraries. With the 1.27.0-wmf.4 branch, you'll have the following line in SyntaxHighlight_GeSHi:
https://github.com/wikimedia/mediawiki-extensions-SyntaxHighlight_GeSHi/blob/wmf/1.27.0-wmf.4/composer.json#L9
"mediawiki/mediawiki-codesniffer": "0.5.0"

in the require-dev section. So far so good. Now, MediaWiki has the following line (same branch):
https://github.com/wikimedia/mediawiki/blob/wmf/1.27.0-wmf.4/composer.json#L42
"mediawiki/mediawiki-codesniffer": "0.4.0",

What happens, if you include/merge both composer.jsons and run composer update. You'll get:

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - The requested package mediawiki/mediawiki-codesniffer 0.5.0 could not be found.

Potential causes:
 - A typo in the package name
 - The package is not available in a stable-enough version according to your minimum-stability setting
   see <https://groups.google.com/d/topic/composer-dev/_g3ASeIFlrc/discussion> for more details.

I'm pretty sure, that the correct way to handle this is to stop the update process, but I wish a better error message, e.g. from composer-merge-plugin, that the dependency from one included json already exists with another version constraint, so you'll get a better indication where you have to look for the/a problem :)

Fatal error on composer run - Call to undefined method Composer\Package\RootAliasPackage::setStabilityFlags

I'm getting a fatal error when trying to run "composer update" or "composer install":

Fatal error: Call to undefined method Composer\Package\RootAliasPackage::setStabilityFlags() in ....web\vendor\wikimedia\composer-merge-plugin\src\MergePlugin.php on line 312

Looking at the code, the function mergeStabilityFlags takes RootPackageInterface as its argument, but this interface doesn't have method setStabilityFlags. It exists only in RootPackage, but not in RootAliasPackage (both implement RootPackageInterface).

I don't fully understand how this works in composer and when RootAliasPackage is used instead of RootPackage, so can't fix it properly. I can add if ($root instanceof RootPackage) in mergeStabilityFlags, but not sure if it's really correct fix.

Question: why "Skipping duplicate" messages?

When running composer update -vvv I always a messages like the one below, for each included composer.json:

[merge-plugin] Skipping duplicate composer.local.json...

None of those files have duplicate references anywhere.

Is this normal and expected?
What does it mean?

Bug on merged autoload.files from included file on root

On the main composer.json I have:

"include": [
  "composer.root.json"
],

On composer.root.json I have:

"autoload": {
  "files": ["private/bootstrap.php"]
}

When I run composer update I get this entry on vendor/composer/autoload_files.php:

return array(
...
  $baseDir . '/cprivate/bootstrap.php',
);

The prepended c seems to come from the included composer.root.json's file name.
If I change the composer.json's include section to:

"include": [
  "./composer.root.json"
],

I get a correct result.
I see this plugin prepends the relative path of each included composer.json file to paths specified on that file's autoload.files section, so this is probably a bug on the algorithm that generates that prefix path.

Fatal error: Class undefined: Composer\Installer\PackageEvents / MergePlugin.php on line 142

Encountered

Installing dependencies (including require-dev)
  - Installing wikimedia/composer-merge-plugin (v1.2.0)
    Downloading: connection...    Failed to download wikimedia/composer-merge-plugin from dist: The "https://api.github.com/repos/wikimedia/composer-merge-plugin/zipball/fa2079fa0bca55a9d053bfd0fb75331423260c18" file could not be downloaded (HTTP/1.1 403 Forbidden)
    Now trying to download from source
- Installing wikimedia/composer-merge-plugin (v1.2.0)
    Cloning fa2079fa0bca55a9d053bfd0fb75331423260c18
Fatal error: Class undefined: Composer\Installer\PackageEvents in /home/travis/build/SemanticMediaWiki/mw/vendor/wikimedia/composer-merge-plugin/src/MergePlugin.php on line 142

on https://travis-ci.org/SemanticMediaWiki/SemanticMediaWiki/jobs/68637285

Debugging output should be written to STDERR

Composer changed its usage of STDOUT and STDERR to match the Unix conventions. this means that STDOUT now only receives the actual output of the command (which could be piped to another program for instance), while using STDERR for all the progression messages meant for the user only.

README needs love

The README needs a Travis badge, a Packagist badge and other good stuff like guidelines for contribution.

Invalid composer.lock when the same requires-dev dependency is present on more than once composer.json

Given two composer.json files, root/composer.json:

{
  "name": "marcos/merget-test",
  "require": {
    "wikimedia/composer-merge-plugin": "~1.3.0"
  },
  "require-dev": {
    "phpunit/phpunit": "^4.8"
  },
  "extra": {
    "merge-plugin": {
      "include": [
        "mods/*/composer.json"
      ]
    }
  }
}

root/mods/test/composer.json:

{
  "name": "marcos/mod-test",
  "require": {
    "monolog/monolog": "^1.19"
  },
  "require-dev": {
    "phpunit/phpunit": "^4.8"
  }
}

When running composer update

Then the composer.lock need to have packages and packages-dev populated.

Error the composer.lock have a packages-dev empty, this causes that development packages get installed when running composer update --no-dev. All the require-dev dependencies are merged, but included in packages instead of packages-dev.

If the requre-dev is only present in one composer.json runs the expected behaviour.

Test errors caused by Composer internal API change

$ composer update
$ composer test
./composer.json is valid
PHP 5.5.19 | 10 parallel jobs
..                                                           2/2 (100 %)


Checked 2 files in 0 seconds, no syntax error found
PHPUnit 4.6.4 by Sebastian Bergmann and contributors.

Configuration read from /Users/bd808/projects/wmf/composer-merge-plugin/phpunit.xml.dist

Deprecated configuration setting "strict" used

.EEEEEE

Time: 1.48 seconds, Memory: 13.00Mb

There were 6 errors:

1) Wikimedia\Composer\MergePluginTest::testOneMergeNoConflicts
Argument 5 passed to Composer\Installer\InstallerEvent::__construct() must implement interface Composer\DependencyResolver\PolicyInterface, instance of Double\Composer\DependencyResolver\Pool\P8 given, called in /Users/bd808/projects/wmf/composer-merge-plugin/tests/phpunit/MergePluginTest.php on line 367 and defined

/Users/bd808/projects/wmf/composer-merge-plugin/tests/phpunit/MergePluginTest.php:367
/Users/bd808/projects/wmf/composer-merge-plugin/tests/phpunit/MergePluginTest.php:95

2) Wikimedia\Composer\MergePluginTest::testRecursiveIncludes
Argument 5 passed to Composer\Installer\InstallerEvent::__construct() must implement interface Composer\DependencyResolver\PolicyInterface, instance of Double\Composer\DependencyResolver\Pool\P15 given, called in /Users/bd808/projects/wmf/composer-merge-plugin/tests/phpunit/MergePluginTest.php on line 367 and defined

/Users/bd808/projects/wmf/composer-merge-plugin/tests/phpunit/MergePluginTest.php:367
/Users/bd808/projects/wmf/composer-merge-plugin/tests/phpunit/MergePluginTest.php:126

3) Wikimedia\Composer\MergePluginTest::testRecursiveIncludesDisabled
Argument 5 passed to Composer\Installer\InstallerEvent::__construct() must implement interface Composer\DependencyResolver\PolicyInterface, instance of Double\Composer\DependencyResolver\Pool\P22 given, called in /Users/bd808/projects/wmf/composer-merge-plugin/tests/phpunit/MergePluginTest.php on line 367 and defined

/Users/bd808/projects/wmf/composer-merge-plugin/tests/phpunit/MergePluginTest.php:367
/Users/bd808/projects/wmf/composer-merge-plugin/tests/phpunit/MergePluginTest.php:160

4) Wikimedia\Composer\MergePluginTest::testOneMergeWithConflicts
Argument 5 passed to Composer\Installer\InstallerEvent::__construct() must implement interface Composer\DependencyResolver\PolicyInterface, instance of Double\Composer\DependencyResolver\Pool\P29 given, called in /Users/bd808/projects/wmf/composer-merge-plugin/tests/phpunit/MergePluginTest.php on line 367 and defined

/Users/bd808/projects/wmf/composer-merge-plugin/tests/phpunit/MergePluginTest.php:367
/Users/bd808/projects/wmf/composer-merge-plugin/tests/phpunit/MergePluginTest.php:210

5) Wikimedia\Composer\MergePluginTest::testMergedRepositories
Argument 5 passed to Composer\Installer\InstallerEvent::__construct() must implement interface Composer\DependencyResolver\PolicyInterface, instance of Double\Composer\DependencyResolver\Pool\P37 given, called in /Users/bd808/projects/wmf/composer-merge-plugin/tests/phpunit/MergePluginTest.php on line 367 and defined

/Users/bd808/projects/wmf/composer-merge-plugin/tests/phpunit/MergePluginTest.php:367
/Users/bd808/projects/wmf/composer-merge-plugin/tests/phpunit/MergePluginTest.php:288

6) Wikimedia\Composer\MergePluginTest::testUpdateStabilityFlags
Argument 5 passed to Composer\Installer\InstallerEvent::__construct() must implement interface Composer\DependencyResolver\PolicyInterface, instance of Double\Composer\DependencyResolver\Pool\P44 given, called in /Users/bd808/projects/wmf/composer-merge-plugin/tests/phpunit/MergePluginTest.php on line 367 and defined

/Users/bd808/projects/wmf/composer-merge-plugin/tests/phpunit/MergePluginTest.php:367
/Users/bd808/projects/wmf/composer-merge-plugin/tests/phpunit/MergePluginTest.php:325

FAILURES!
Tests: 7, Assertions: 34, Errors: 6.

The signature for Composer\Installer\InstallerEvent changed in composer@3efed22. As a bonus it changed by inserting a new required parameter into the middle of the signature.

[FR] Add merge `autoload` and resolve paths

It would be great if this addon also supported merging of PSR-4 autoload classes:

"autoload": {
    "psr-4": {
        "Boardworld\\": "app/third_party/boardworld/src/"
    }
}

Additionally relative paths in included composer files should have their paths resolved correctly.

aliases on requires from included configs don't seem to work

I have a composer.json with a requirement on package A and a requirement on package B:

{
  "require": {
    "A": "dev-trunk",
    "B": "dev-trunk"
  }
}

package B also has a requirement on package A @ dev-trunk.

If I try to change the version of package A in my secondary config file with something like:

{
  "require": {
    "A": "dev-feature as dev-trunk"
  }
}

I would expect this to work fine because the alias statement should then mean package B's need for A @ dev-trunk will still be met (via the alias).

However, I get a conflict resolution failure.

The output differs depending on whether I have "replace" mode true or false but the end result is the same failure to resolve.

Tag v1.3.1

#102 has been merged, containing a critical bug fix for Drupal.

Basically, people who removed Drupal's .git repository (or used a dist package) were completely unable to install additional packages. That's now fixed, and we must update composer-merge-plugin that ships with Drupal. A new release would help :)

Merging VCS repository override of published package fails

First reported by @ghprod in #71 (comment)

composer.json:

{
    "require": {
        "wikimedia/composer-merge-plugin": "dev-master"
    },
    "config": {
        "preferred-install": "dist"
    },
    "extra": {
        "merge-plugin": {
            "include": "composer.local.json"
        }
    }
}

composer.local.json:

{
    "repositories": [
        {
            "type": "vcs",
            "url": "https://github.com/ghprod/laravel-menu"
        }
    ],
    "require":{
        "lavary/laravel-menu": "dev-master#956e50f"
    }
}

Result:

$ composer -vvv update
[...snip...]
Loading plugin Wikimedia\Composer\MergePlugin
  [merge-plugin] Loading composer.local.json...
  [merge-plugin] Adding vcs repository github.com/ghprod/laravel-menu
  [merge-plugin] Merging lavary/laravel-menu
Loading composer repositories with package information
[...snip...]
Downloading https://api.github.com/repos/ghprod/laravel-menu
Downloading https://api.github.com/repos/ghprod/laravel-menu/contents/composer.json?ref=master
Downloading https://api.github.com/repos/ghprod/laravel-menu/commits/master
Downloading https://api.github.com/repos/ghprod/laravel-menu/tags?per_page=100
Downloading https://api.github.com/repos/ghprod/laravel-menu/git/refs/heads?per_page=100
[...snip...]
Reading composer.json of lavary/laravel-menu (master)
Downloading https://api.github.com/repos/ghprod/laravel-menu/contents/composer.json?ref=956e50fbf0d99b2804539069b012ad52b4851dd2
Downloading https://api.github.com/repos/ghprod/laravel-menu/commits/956e50fbf0d99b2804539069b012ad52b4851dd2
[...snip...]
Downloading http://packagist.org/p/lavary/laravel-menu%24cb8432bd74b707af0300352a1d49742389810f45e5646550e5dca3a823fe4c55.json
[...snip...]
Analyzed 1426 packages to resolve dependencies
Analyzed 1200 rules to resolve dependencies
[...snip...]
  - Installing lavary/laravel-menu (dev-master bebce99)
Downloading https://api.github.com/repos/lavary/laravel-menu/zipball/bebce996ef08cf911da0139c30a2da03a2768326

The installed revision (bebce99) is the head of the dev branch of the project as listed on Packagist. The alternate VCS repository was not used.

If the require for "lavary/laravel-menu" is moved to composer.json, results are slightly different but still not correct. In that case the logs report:

  - Installing lavary/laravel-menu (dev-master 956e50f)
Downloading https://api.github.com/repos/lavary/laravel-menu/zipball/956e50f

This download is still from the wrong repository in this case and the files fetched from GitHub are not not actually for the desired hash.

If the "repositories" are moved to composer.json instead, the new output is:

  - Installing lavary/laravel-menu (dev-master 956e50f)
Downloading https://api.github.com/repos/ghprod/laravel-menu/zipball/956e50fbf0d99b2804539069b012ad52b4851dd2

This is the desired result for all three tests.

I think the issue here is the order that the repositories are added to Composer\Repository\RepositoryManager. It may take an upstream patch to fix this properly.

Not using revisions

When I add a revision for a project in a "merged" composer.json, composer does not respect the commiit, like:

"require": {
    "drupal/config_devel": "dev-8.x-1.x#d4cdd21"
},

Instead of using revision d4cdd21 it using the latest from HEAD. With a "normal" composer.json (not merged) it works and uses correct revision.

does post-update-cmd get merged?

Hi, I was wondering that there is no mention whether the events get merged or not?
I was trying post-update-cmd to be merged but it doesn't.

Don't silently ignore when declared inclusion files don't exist

When having a composer.local.json like follows:

{
    "extra": {
        "merge-plugin": {
            "include": [
                "foo/bar/composer.json"
            ]
        }
    }
}

Where foo/bar does not exist, there is no error from running composer update.

For MediaWiki core this is convenient since existence of composer.local.json itself is optional. And things like * matches for subdirectories may also legitimately yield no matches. But when specifying an exact file it should report an error to catch regressions, typos etc.

This is a known problem in many libraries that pull everything through pattern-matchers (same in Grunt often), but should be fixable hopefully.

Minimum stability not updated by merged settings

The stability flags of the root package are not modified by the addition of merged requirements. This can lead to the solver reporting that a package cannot be installed because "the package is not available in a stable-enough version according to your minimum-stability setting".

When a requirement is given directly in the root package the stability of each package is assessed by RootPackageLoader and the set of found stability flags is stored in the package. This data is used by Pool::isPackageAcceptable() to determine if installing a given package is allowed.

The naive fix for this would be to inject all possible stability flags into the root package, but it should be possible to parse and inject only the explicitly requested stability flags by parsing each requirement using VersionParser::parseStability().

Breaking API-change introduced in Composer 1.1 branch

Supposedly a breaking API-change was introduced in Composer 1.1 branch (Composer version 1.1.0 2016-05-10 15:21:19):

The "wikimedia/composer-merge-plugin" plugin was skipped because it requires a Plugin API version ("1.0.0") that does not match your Composer installation ("1.1.0"). You may need to run composer update with the "--no-plugins" option.

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - wikimedia/composer-merge-plugin v1.0.0 requires composer-plugin-api 1.0.0 -> no matching package found.
    - wikimedia/composer-merge-plugin v1.0.0 requires composer-plugin-api 1.0.0 -> no matching package found.
    - Installation request for wikimedia/composer-merge-plugin 1.0.0 -> satisfiable by wikimedia/composer-merge-plugin[v1.0.0].

I will downgrade to the Composer 1.0 branch which hopefully helps to avoid the issue for now.

Update on initial install

See #34 (comment)

When using Travis CI or using a deployment tool such as Capifony/Capistrano (or whenever installing dependencies for the first time), the plugin runs a composer update after your composer install, causing any newer versions to be installed (contrary to what's in your lock file).

As it stands, a second composer install has to be run to force it back to the expected state.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.