Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Composer v2 #189

Merged
merged 20 commits into from
Feb 12, 2021
Merged

Conversation

mcaskill
Copy link
Contributor

@mcaskill mcaskill commented Sep 28, 2020

Latest Update 2021-01-25 14:25 EST

Notes:

  1. Avoid unnecessary issue bumping. Please test this pull request and report issues or approve working state.
    See comment.
  2. Stability of this pull request's changeset needs additional testing from the community, such as unintentional updates upon requiring this plugin.
    See comment.
  3. Project is stuck in the process of transferring ownership to a new team within the Wikimedia Foundation.
    See comment.
  4. Since v1.4 of the plugin does not support Composer v2, the plugin is ignored when updating to v1.5. As a result, Composer is unaware of the merged dependencies and removes them. Either update the plugin with Composer v1 first or run composer update again.
    See comment.
  5. Unintentional lock file updates caused by isFirstInstall() on Composer v2. Listening only to post-update-cmd instead of post-install-cmd might be more sensible.
    See comment and followup.
  6. Please be patient, we don't want to push broken changes.

How to test:

{
    "repositories": [
        {
            "type":"vcs",
            "url":"https://github.com/mcaskill/composer-merge-plugin"
        }
    ],
    "require": {
        "wikimedia/composer-merge-plugin": "dev-feature/composer-v2 as 1.5.0"
    }
}

Tasks:


Replaces #187, #185, as fix for #184 (as per composer/composer#8726)

I've tested using the example and the unit tests and it works in Composer v1 and v2.

This alternative proposal forgoes PRE_DEPENDENCIES_SOLVING entirely to avoid over-complicating the codebase and streamline the plugin's merge logic.

The issue with the previous attempts (as well as attempts on other plugins) stems from a miscommunication from the Composer team of the major difference in how v1 and v2 resolve and install dependencies.

[…] Roughly speaking:

  • Composer v1: Composer resolves dependencies (dispatching *_DEPENDENCIES_SOLVING), iterates packages (while dispatching PRE_PACKAGE_* before PRE_FILE_DOWNLOAD), then finally writes the lock file.
  • Composer v2: Composer resolves dependencies (dispatching PRE_POOL_CREATE), writes the lock file, dispatches PRE_OPERATIONS_EXEC, downloads the packages (while dispatching PRE_FILE_DOWNLOAD), then iterates packages (while dispatching PRE_PACKAGE_*).

In particular, people are assuming that PRE_OPERATIONS_EXEC is a replacement for PRE_DEPENDENCIES_SOLVING since they are dispatched in a similar-looking routine. The closest event to the latter would actually be PRE_POOL_CREATE.
composer/composer#8726

Back to my proposal.

Currently, the use of PRE_DEPENDENCIES_SOLVING in the plugin is used to inject duplicate requirements (usually with a different version constraints) into the solver (while distinguishing between require and require-dev).

What I propose replaces the duplicate links tracking in ExtraPackage by back porting Composer 2's new static MultiConstraint::create() method which can be used to resolve complex-constraints early on. In turn, this makes the need for PRE_DEPENDENCIES_SOLVING obsolete.

I hope this PR will, at the very least, help to figure out how to support Composer v2.

@LukeTowers
Copy link

@tobias-kuendig could you test this with October & Composer 1.0 & 2.0?

@mcaskill
Copy link
Contributor Author

mcaskill commented Oct 24, 2020

Note: I last tested these changes with Composer v1.10.15 / v2.0.2. I do am unaware if it works in latest versions.

@atapatel
Copy link

When will it release for composer 2.0 ?

@Dmi3yy
Copy link

Dmi3yy commented Oct 27, 2020

are looking forward to

@dereuromark dereuromark mentioned this pull request Oct 27, 2020
@terabytesoftw
Copy link

Thanks for the huge work, any ideas when it will merge.

@sebschaefer
Copy link

Tested with Composer 2.0.3. Works for me. Thanks!

@ivi3
Copy link

ivi3 commented Oct 30, 2020

@sebschaefer how you solved that?
which version do u use?

@mlocati
Copy link

mlocati commented Oct 30, 2020

You can check this PR in your projects by requiring wikimedia/composer-merge-plugin:dev-feature/composer-v2 and adding the https://github.com/mcaskill/composer-merge-plugin.git vcs repository to your composer.json file.

I just checked this with concrete5 and this PR fixes the issue.

@FlorentTorregrosa
Copy link

Hello,

Thanks to everyone involved in this PR.

@leoloso
Copy link

leoloso commented Nov 2, 2020

This PR worked for me too, thanks!

@prudloff-insite
Copy link

This PR seems to work mostly correctly.
However, I am getting this error when installing with Composer 1.10.1:

PHP Fatal error:  Uncaught Error: Call to undefined method Composer\Factory::getLockFile() in /mnt/data/workspace/drupal_d9/vendor/wikimedia/composer-merge-plugin/src/MergePlugin.php:323
Stack trace:
#0 [internal function]: Wikimedia\Composer\MergePlugin->onPostInstallOrUpdate()
#1 /usr/share/php/Composer/EventDispatcher/EventDispatcher.php(164): call_user_func()
#2 /usr/share/php/Composer/EventDispatcher/EventDispatcher.php(96): Composer\EventDispatcher\EventDispatcher->doDispatch()
#3 /usr/share/php/Composer/Installer.php(338): Composer\EventDispatcher\EventDispatcher->dispatchScript()
#4 /usr/share/php/Composer/Command/InstallCommand.php(122): Composer\Installer->run()
#5 /usr/share/php/Symfony/Component/Console/Command/Command.php(255): Composer\Command\InstallCommand->execute()
#6 /usr/share/php/Symfony/Component/Console/Application.php(934): Symfony\Component\Console\Command\Command->run()
#7 /usr/share/php/Symfony/Component/Console/Application.php(273): Symfony\Component\Console\Application->doRunCommand()
#8 /usr/share in /mnt/data/workspace/drupal_d9/vendor/wikimedia/composer-merge-plugin/src/MergePlugin.php on line 323

Fatal error: Uncaught Error: Call to undefined method Composer\Factory::getLockFile() in /mnt/data/workspace/drupal_d9/vendor/wikimedia/composer-merge-plugin/src/MergePlugin.php:323
Stack trace:
#0 [internal function]: Wikimedia\Composer\MergePlugin->onPostInstallOrUpdate()
#1 /usr/share/php/Composer/EventDispatcher/EventDispatcher.php(164): call_user_func()
#2 /usr/share/php/Composer/EventDispatcher/EventDispatcher.php(96): Composer\EventDispatcher\EventDispatcher->doDispatch()
#3 /usr/share/php/Composer/Installer.php(338): Composer\EventDispatcher\EventDispatcher->dispatchScript()
#4 /usr/share/php/Composer/Command/InstallCommand.php(122): Composer\Installer->run()
#5 /usr/share/php/Symfony/Component/Console/Command/Command.php(255): Composer\Command\InstallCommand->execute()
#6 /usr/share/php/Symfony/Component/Console/Application.php(934): Symfony\Component\Console\Command\Command->run()
#7 /usr/share/php/Symfony/Component/Console/Application.php(273): Symfony\Component\Console\Application->doRunCommand()
#8 /usr/share in /mnt/data/workspace/drupal_d9/vendor/wikimedia/composer-merge-plugin/src/MergePlugin.php on line 323

(Only the first time, the next composer install don't trigger the error.)

@mcaskill
Copy link
Contributor Author

mcaskill commented Nov 2, 2020

[…] I am getting this error when installing with Composer 1.10.1:

@prudloff-insite Thanks, I'll check this out.

@prudloff-insite
Copy link

Also it looks like the plugin now runs composer update after the first install?
This is a problem when running composer install on a CI.
We expect the locked dependencies to be installed as is and not everything to be updated.

@mcaskill
Copy link
Contributor Author

mcaskill commented Nov 2, 2020

Also it looks like the plugin now runs composer update after the first install?
This is a problem when running composer install on a CI.
We expect the locked dependencies to be installed as is and not everything to be updated.

@prudloff-insite Good point! I had a feeling there was some flaw.

When the plugin is first installed, it triggers a second install / update.

In Composer 2, I'm forcing an update to add the inherited dependencies to the lock file but this is clearly an issue with existing root dependencies that might not want to be updated.

I'll try to look into it soon. If you have any suggestions, I'm all ears.

@prudloff-insite
Copy link

Would it be possible to run composer update only on dependencies from the merged file?

Or at least add a flag that we can use on the CI to tell it not to update the lock file.

src/MergePlugin.php Outdated Show resolved Hide resolved
$event->getComposer()->getLocker()->isLocked()
);
} else {
$this->state->setLocked(false);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Find alternative to install inherited dependencies without affecting locked dependencies.

Also it looks like the plugin now runs composer update after the first install?
This is a problem when running composer install on a CI.
We expect the locked dependencies to be installed as is and not everything to be updated.

Originally posted by @prudloff-insite in #189 (comment)

Copy link
Contributor Author

@mcaskill mcaskill Nov 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could maybe be resolved using setUpdateAllowList() with setAllowListTransitiveDependencies() in Composer 1 and setUpdateAllowTransitiveDependencies() in Composer 2.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@prudloff-insite Can you provide me a copy of the composer.json and composer.lock that should not be updated when requiring the composer-merge-plugin?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is a minimal Drupal project that reproduces our issue: https://gist.github.com/prudloff-insite/d4523328892937091b5b43f1e95919fc

The first time a contributor calls composer install with Composer 2, it will run composer update and modify the lock file.
IMHO composer install should never modify the lock file, only composer update or composer require should try to pick up new merged dependencies.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I'll give this a try as soon as I can.

I did some tests over the weekend and I wasn't able to reproduce the issue despite knowing why it would occur.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to agree with @prudloff-insite , install should never run update. This is causing havoc in our CI as well. It is unexpectedly (and unnecessarily) updating packages without consent. Luckily this is stopped by our CI comparing locks before proceeding, but this could be a major issue for others without that stop-gap. I think the original method of checking lock is fine and it's expected that a user runs composer update locally as part of their update to composer 2 (which is also noted in the README).

Possibly even just adding a note instead to the console "This appears to be your first install, run composer update to xxx......."

@mcaskill
Copy link
Contributor Author

mcaskill commented Feb 7, 2021

I've implemented Installer::setUpdateAllowList(), this should provide consistent first-install between Composer 1 and 2.

@prudloff-insite Can you test this out on your end? Thanks.

I used the Composer files you shared with me, back in November, and things appear to be working as intended.

@reedy
Copy link
Member

reedy commented Feb 7, 2021

Trying to update to composer 2.0 and plugin 1.5 in one go (still needs two composer update as discussed):

$ php ../composer-2.0.phar update
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.
> ComposerHookHandler::onPreUpdate
Loading composer repositories with package information
Updating dependencies                                 
Lock file operations: 1 install, 1 update, 24 removals
  - Removing beberlei/assert (v3.3.0)
  - Removing brick/math (0.9.2)
  - Removing christian-riesen/base32 (1.4.0)
  - Removing defuse/php-encryption (v2.2.1)
  - Removing fgrosse/phpasn1 (v2.2.0)
  - Removing firebase/php-jwt (v5.2.0)
  - Removing jakobo/hotp-php (v2.0.0)
  - Removing lcobucci/jwt (3.4.3)
  - Removing league/event (2.2.0)
  - Removing league/oauth2-server (dev-v9.0.0-alpha a00cc3c)
  - Removing league/uri (6.4.0)
  - Removing league/uri-components (2.3.0)
  - Removing league/uri-interfaces (2.2.0)
  - Removing psr/http-factory (1.0.1)
  - Removing ramsey/collection (1.1.3)
  - Removing ramsey/uuid (4.1.1)
  - Removing spomky-labs/base64url (v2.0.4)
  - Removing spomky-labs/cbor-php (v2.0.1)
  - Removing symfony/process (v5.2.3)
  - Removing web-auth/cose-lib (v3.2.10)
  - Removing web-auth/metadata-service (v3.2.10)
  - Removing web-auth/webauthn-lib (v3.2.10)
  - Removing wikimedia/css-sanitizer (v3.0.1)
  - Removing wikimedia/equivset (1.4.2)
  - Upgrading wikimedia/composer-merge-plugin (v1.4.1 => dev-feature/composer-v2 4195d45)
  - Locking wikimedia/shellbox (1.0.1)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 1 install, 1 update, 24 removals
  - Syncing wikimedia/composer-merge-plugin (dev-feature/composer-v2 4195d45) into cache
  - Downloading wikimedia/shellbox (1.0.1)
  - Removing wikimedia/equivset (1.4.2)
  - Removing wikimedia/css-sanitizer (v3.0.1)
  - Removing web-auth/webauthn-lib (v3.2.10)
  - Removing web-auth/metadata-service (v3.2.10)
  - Removing web-auth/cose-lib (v3.2.10)
  - Removing symfony/process (v5.2.3)
  - Removing spomky-labs/cbor-php (v2.0.1)
  - Removing spomky-labs/base64url (v2.0.4)
  - Removing ramsey/uuid (4.1.1)
  - Removing ramsey/collection (1.1.3)
  - Removing psr/http-factory (1.0.1)
  - Removing league/uri-interfaces (2.2.0)
  - Removing league/uri-components (2.3.0)
  - Removing league/uri (6.4.0)
  - Removing league/oauth2-server (dev-v9.0.0-alpha a00cc3c)
  - Removing league/event (2.2.0)
  - Removing lcobucci/jwt (3.4.3)
  - Removing jakobo/hotp-php (v2.0.0)
  - Removing firebase/php-jwt (v5.2.0)
  - Removing fgrosse/phpasn1 (v2.2.0)
  - Removing defuse/php-encryption (v2.2.1)
  - Removing christian-riesen/base32 (1.4.0)
  - Removing brick/math (0.9.2)
  - Removing beberlei/assert (v3.3.0)
  - Upgrading wikimedia/composer-merge-plugin (v1.4.1 => dev-feature/composer-v2 4195d45): Checking out 4195d45d1c from cache
  - Installing wikimedia/shellbox (1.0.1): Extracting archive
Package phpunit/php-token-stream is abandoned, you should avoid using it. No replacement was suggested.
Generating optimized autoload files
composer/package-versions-deprecated: Generating version class...
composer/package-versions-deprecated: ...done generating version class
39 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> ComposerVendorHtaccessCreator::onEvent
$ php ../composer-2.0.phar update
> ComposerHookHandler::onPreUpdate
Loading composer repositories with package information
Updating dependencies                                 
Lock file operations: 24 installs, 0 updates, 0 removals
  - Locking beberlei/assert (v3.3.0)
  - Locking brick/math (0.9.2)
  - Locking christian-riesen/base32 (1.4.0)
  - Locking defuse/php-encryption (v2.2.1)
  - Locking fgrosse/phpasn1 (v2.2.0)
  - Locking firebase/php-jwt (v5.2.0)
  - Locking jakobo/hotp-php (v2.0.0)
  - Locking lcobucci/jwt (3.4.3)
  - Locking league/event (2.2.0)
  - Locking league/oauth2-server (dev-v9.0.0-alpha a00cc3c)
  - Locking league/uri (6.4.0)
  - Locking league/uri-components (2.3.0)
  - Locking league/uri-interfaces (2.2.0)
  - Locking psr/http-factory (1.0.1)
  - Locking ramsey/collection (1.1.3)
  - Locking ramsey/uuid (4.1.1)
  - Locking spomky-labs/base64url (v2.0.4)
  - Locking spomky-labs/cbor-php (v2.0.1)
  - Locking symfony/process (v5.2.3)
  - Locking web-auth/cose-lib (v3.2.10)
  - Locking web-auth/metadata-service (v3.2.10)
  - Locking web-auth/webauthn-lib (v3.2.10)
  - Locking wikimedia/css-sanitizer (v3.0.1)
  - Locking wikimedia/equivset (1.4.2)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 24 installs, 0 updates, 0 removals
  - Syncing league/oauth2-server (dev-v9.0.0-alpha a00cc3c) into cache
  - Installing brick/math (0.9.2): Extracting archive
  - Installing christian-riesen/base32 (1.4.0): Extracting archive
  - Installing fgrosse/phpasn1 (v2.2.0): Extracting archive
  - Installing firebase/php-jwt (v5.2.0): Extracting archive
  - Installing jakobo/hotp-php (v2.0.0): Extracting archive
  - Installing league/event (2.2.0): Extracting archive
  - Installing lcobucci/jwt (3.4.3): Extracting archive
  - Installing defuse/php-encryption (v2.2.1): Extracting archive
  - Installing league/oauth2-server (dev-v9.0.0-alpha a00cc3c): Cloning a00cc3c274 from cache
  - Installing league/uri-interfaces (2.2.0): Extracting archive
  - Installing league/uri (6.4.0): Extracting archive
  - Installing league/uri-components (2.3.0): Extracting archive
  - Installing ramsey/collection (1.1.3): Extracting archive
  - Installing psr/http-factory (1.0.1): Extracting archive
  - Installing beberlei/assert (v3.3.0): Extracting archive
  - Installing web-auth/metadata-service (v3.2.10): Extracting archive
  - Installing web-auth/cose-lib (v3.2.10): Extracting archive
  - Installing symfony/process (v5.2.3): Extracting archive
  - Installing spomky-labs/cbor-php (v2.0.1): Extracting archive
  - Installing spomky-labs/base64url (v2.0.4): Extracting archive
  - Installing ramsey/uuid (4.1.1): Extracting archive
  - Installing web-auth/webauthn-lib (v3.2.10): Extracting archive
  - Installing wikimedia/css-sanitizer (v3.0.1): Extracting archive
  - Installing wikimedia/equivset (1.4.2): Extracting archive
12 package suggestions were added by new dependencies, use `composer suggest` to see details.
Package phpunit/php-token-stream is abandoned, you should avoid using it. No replacement was suggested.
Generating optimized autoload files
composer/package-versions-deprecated: Generating version class...
composer/package-versions-deprecated: ...done generating version class
51 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> ComposerVendorHtaccessCreator::onEvent

No vendor repo, 1.4.1 and composer 1.x

$ php ../composer.phar update
> ComposerHookHandler::onPreUpdate
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 121 installs, 0 updates, 0 removals
  - Installing wikimedia/composer-merge-plugin (v1.4.1): Loading from cache
  - Installing composer/package-versions-deprecated (1.11.99.1): Loading from cache
  - Installing cssjanus/cssjanus (v1.3.0): Loading from cache
  - Installing oojs/oojs-ui (v0.41.1): Loading from cache
  - Installing pear/pear_exception (v1.0.1): Loading from cache
  - Installing pear/console_getopt (v1.4.3): Loading from cache
  - Installing pear/pear-core-minimal (v1.10.10): Loading from cache
  - Installing pear/mail (v1.4.1): Loading from cache
  - Installing pear/mail_mime (1.10.9): Loading from cache
  - Installing pear/net_socket (v1.2.2): Loading from cache
  - Installing pear/net_smtp (1.9.2): Loading from cache
  - Installing pear/net_url2 (v2.2.2): Loading from cache
  - Installing wikimedia/base-convert (v2.0.1): Loading from cache
  - Installing wikimedia/cdb (1.4.1): Loading from cache
  - Installing wikimedia/cldr-plural-rule-parser (v1.0.0): Loading from cache
  - Installing pleonasm/bloom-filter (1.0.2): Loading from cache
  - Installing wikimedia/common-passwords (0.2.0): Loading from cache
  - Installing wikimedia/html-formatter (2.0.1): Loading from cache
  - Installing wikimedia/at-ease (v2.0.0): Loading from cache
  - Installing wikimedia/ip-set (2.1.0): Loading from cache
  - Installing wikimedia/less.php (v3.1.0): Loading from cache
  - Installing psr/log (1.1.3): Loading from cache
  - Installing wikimedia/php-session-serializer (v1.0.7): Loading from cache
  - Installing wikimedia/purtle (v1.0.7): Loading from cache
  - Installing wikimedia/relpath (2.1.1): Loading from cache
  - Installing wikimedia/running-stat (v1.2.1): Loading from cache
  - Installing wikimedia/scoped-callback (v3.0.0): Loading from cache
  - Installing wikimedia/assert (v0.5.0): Loading from cache
  - Installing psr/container (1.0.0): Loading from cache
  - Installing wikimedia/services (2.0.1): Loading from cache
  - Installing wikimedia/wikipeg (2.0.5): Loading from cache
  - Installing monolog/monolog (2.2.0): Loading from cache
  - Installing psr/http-message (1.0.1): Loading from cache
  - Installing psr/http-client (1.0.1): Loading from cache
  - Installing ralouphie/getallheaders (3.0.3): Loading from cache
  - Installing guzzlehttp/psr7 (1.7.0): Loading from cache
  - Installing guzzlehttp/promises (1.4.0): Loading from cache
  - Installing guzzlehttp/guzzle (7.2.0): Loading from cache
  - Installing wikimedia/shellbox (1.0.1): Loading from cache
  - Installing wikimedia/utfnormal (3.0.1): Loading from cache
  - Installing wikimedia/wait-condition-loop (v1.0.1): Loading from cache
  - Installing wikimedia/wrappedstring (v3.2.0): Loading from cache
  - Installing wikimedia/timestamp (v3.0.0): Loading from cache
  - Installing wikimedia/xmp-reader (0.8.0): Loading from cache
  - Installing zordius/lightncandy (v1.2.5): Loading from cache
  - Installing doctrine/sql-formatter (1.1.1): Loading from cache
  - Installing giorgiosironi/eris (0.10.0): Loading from cache
  - Installing squizlabs/php_codesniffer (3.5.8): Loading from cache
  - Installing composer/spdx-licenses (1.5.4): Loading from cache
  - Installing composer/semver (3.2.4): Loading from cache
  - Installing mediawiki/mediawiki-codesniffer (v35.0.0): Loading from cache
  - Installing symfony/polyfill-php80 (v1.22.0): Loading from cache
  - Installing symfony/polyfill-intl-normalizer (v1.22.0): Loading from cache
  - Installing symfony/polyfill-intl-grapheme (v1.22.0): Loading from cache
  - Installing symfony/string (v5.2.3): Loading from cache
  - Installing symfony/service-contracts (v2.2.0): Loading from cache
  - Installing symfony/polyfill-php73 (v1.22.0): Loading from cache
  - Installing symfony/console (v5.2.3): Loading from cache
  - Installing sabre/event (5.1.2): Loading from cache
  - Installing netresearch/jsonmapper (v2.1.0): Loading from cache
  - Installing microsoft/tolerant-php-parser (v0.0.23): Loading from cache
  - Installing phpdocumentor/reflection-common (2.2.0): Loading from cache
  - Installing webmozart/assert (1.9.1): Loading from cache
  - Installing phpdocumentor/type-resolver (1.4.0): Loading from cache
  - Installing phpdocumentor/reflection-docblock (5.2.2): Loading from cache
  - Installing felixfbecker/advanced-json-rpc (v3.2.0): Loading from cache
  - Installing composer/xdebug-handler (1.4.5): Loading from cache
  - Installing phan/phan (3.2.6): Loading from cache
  - Installing mediawiki/phan-taint-check-plugin (3.2.1): Loading from cache
  - Installing mediawiki/mediawiki-phan-config (0.10.6): Loading from cache
  - Installing nmred/kafka-php (v0.1.5): Loading from cache
  - Installing php-parallel-lint/php-console-color (v0.3): Loading from cache
  - Installing php-parallel-lint/php-console-highlighter (v0.5): Loading from cache
  - Installing php-parallel-lint/php-parallel-lint (v1.2.0): Loading from cache
  - Installing pimple/pimple (v3.3.1): Loading from cache
  - Installing dnoegel/php-xdg-base-dir (v0.1.1): Loading from cache
  - Installing nikic/php-parser (v4.10.2): Loading from cache
  - Installing symfony/var-dumper (v5.2.3): Loading from cache
  - Installing psy/psysh (v0.10.5): Loading from cache
  - Installing seld/jsonlint (1.8.3): Loading from cache
  - Installing wikimedia/avro (v1.9.0): Loading from cache
  - Installing wikimedia/testing-access-wrapper (2.0.0): Loading from cache
  - Installing wikimedia/zest-css (1.1.4): Loading from cache
  - Installing wikimedia/remex-html (2.2.2): Loading from cache
  - Installing wikimedia/object-factory (v3.0.0): Loading from cache
  - Installing wikimedia/ip-utils (3.0.1): Loading from cache
  - Installing liuggio/statsd-php-client (v1.0.18): Loading from cache
  - Installing wikimedia/parsoid (v0.13.0-a24): Loading from cache
  - Installing doctrine/event-manager (1.1.1): Loading from cache
  - Installing doctrine/cache (1.10.2): Loading from cache
  - Installing doctrine/dbal (3.0.0): Loading from cache
  - Installing sebastian/version (2.0.1): Loading from cache
  - Installing sebastian/type (1.1.4): Loading from cache
  - Installing sebastian/resource-operations (2.0.2): Loading from cache
  - Installing sebastian/recursion-context (3.0.1): Loading from cache
  - Installing sebastian/object-reflector (1.1.2): Loading from cache
  - Installing sebastian/object-enumerator (3.0.4): Loading from cache
  - Installing sebastian/global-state (3.0.1): Loading from cache
  - Installing sebastian/exporter (3.1.3): Loading from cache
  - Installing sebastian/environment (4.2.4): Loading from cache
  - Installing sebastian/diff (3.0.3): Loading from cache
  - Installing sebastian/comparator (3.0.3): Loading from cache
  - Installing phpunit/php-timer (2.1.3): Loading from cache
  - Installing phpunit/php-text-template (1.2.1): Loading from cache
  - Installing phpunit/php-file-iterator (2.0.3): Loading from cache
  - Installing theseer/tokenizer (1.2.0): Loading from cache
  - Installing sebastian/code-unit-reverse-lookup (1.0.2): Loading from cache
  - Installing phpunit/php-token-stream (4.0.4): Loading from cache
  - Installing phpunit/php-code-coverage (7.0.14): Loading from cache
  - Installing doctrine/instantiator (1.4.0): Loading from cache
  - Installing phpspec/prophecy (1.12.2): Loading from cache
  - Installing myclabs/deep-copy (1.10.2): Loading from cache
  - Installing phar-io/version (3.0.4): Loading from cache
  - Installing phar-io/manifest (2.0.1): Loading from cache
  - Installing phpunit/phpunit (8.5.14): Loading from cache
  - Installing johnkary/phpunit-speedtrap (v3.3.0): Loading from cache
  - Installing justinrainbow/json-schema (5.2.10): Loading from cache
  - Installing symfony/deprecation-contracts (v2.2.0): Loading from cache
  - Installing symfony/yaml (v5.2.3): Loading from cache
  - Installing hamcrest/hamcrest-php (v2.0.1): Loading from cache
  - Installing wmde/hamcrest-html-matchers (v0.1.1): Loading from cache
pear/net_smtp suggests installing pear/auth_sasl (Install optionally via your project's composer.json)
monolog/monolog suggests installing graylog2/gelf-php (Allow sending log messages to a GrayLog2 server)
monolog/monolog suggests installing doctrine/couchdb (Allow sending log messages to a CouchDB server)
monolog/monolog suggests installing ruflin/elastica (Allow sending log messages to an Elastic Search server)
monolog/monolog suggests installing elasticsearch/elasticsearch (Allow sending log messages to an Elasticsearch server via official client)
monolog/monolog suggests installing php-amqplib/php-amqplib (Allow sending log messages to an AMQP server using php-amqplib)
monolog/monolog suggests installing ext-amqp (Allow sending log messages to an AMQP server (1.0+ required))
monolog/monolog suggests installing ext-mongodb (Allow sending log messages to a MongoDB server (via driver))
monolog/monolog suggests installing mongodb/mongodb (Allow sending log messages to a MongoDB server (via library))
monolog/monolog suggests installing aws/aws-sdk-php (Allow sending log messages to AWS services like DynamoDB)
monolog/monolog suggests installing rollbar/rollbar (Allow sending log messages to Rollbar)
monolog/monolog suggests installing php-console/php-console (Allow sending log messages to Google Chrome)
guzzlehttp/psr7 suggests installing laminas/laminas-httphandlerrunner (Emit PSR-7 responses)
giorgiosironi/eris suggests installing icomefromthenet/reverse-regex (v0.0.6.3 for the regex() Generator)
symfony/service-contracts suggests installing symfony/service-implementation
symfony/console suggests installing symfony/event-dispatcher
symfony/console suggests installing symfony/lock
symfony/console suggests installing symfony/process
psy/psysh suggests installing ext-pdo-sqlite (The doc command requires SQLite to work.)
psy/psysh suggests installing hoa/console (A pure PHP readline implementation. You'll want this if your PHP install doesn't already support readline or libedit.)
wikimedia/parsoid suggests installing wikimedia/langconv (Provides script conversion support)
doctrine/cache suggests installing alcaeus/mongo-php-adapter (Required to use legacy MongoDB driver)
sebastian/global-state suggests installing ext-uopz (*)
phpunit/phpunit suggests installing phpunit/php-invoker (^2.0.0)
phpunit/phpunit suggests installing ext-soap (*)
Package phpunit/php-token-stream is abandoned, you should avoid using it. No replacement was suggested.
Writing lock file
Generating optimized autoload files
composer/package-versions-deprecated: Generating version class...
composer/package-versions-deprecated: ...done generating version class
39 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> ComposerHookHandler::onPreUpdate
Loading composer repositories with package information
Updating dependencies (including require-dev)         
Package operations: 24 installs, 0 updates, 0 removals
  - Installing firebase/php-jwt (v5.2.0): Loading from cache
  - Installing defuse/php-encryption (v2.2.1): Loading from cache
  - Installing lcobucci/jwt (3.4.3): Loading from cache
  - Installing league/event (2.2.0): Loading from cache
  - Installing league/oauth2-server (dev-v9.0.0-alpha a00cc3c): Cloning a00cc3c274 from cache
  - Installing christian-riesen/base32 (1.4.0): Loading from cache
  - Installing jakobo/hotp-php (v2.0.0): Loading from cache
  - Installing psr/http-factory (1.0.1): Loading from cache
  - Installing league/uri-interfaces (2.2.0): Loading from cache
  - Installing league/uri-components (2.3.0): Loading from cache
  - Installing league/uri (6.4.0): Loading from cache
  - Installing beberlei/assert (v3.3.0): Loading from cache
  - Installing web-auth/metadata-service (v3.2.10): Loading from cache
  - Installing fgrosse/phpasn1 (v2.2.0): Loading from cache
  - Installing web-auth/cose-lib (v3.2.10): Loading from cache
  - Installing symfony/process (v5.2.3): Loading from cache
  - Installing brick/math (0.9.2): Loading from cache
  - Installing spomky-labs/cbor-php (v2.0.1): Loading from cache
  - Installing spomky-labs/base64url (v2.0.4): Loading from cache
  - Installing ramsey/collection (1.1.3): Loading from cache
  - Installing ramsey/uuid (4.1.1): Loading from cache
  - Installing web-auth/webauthn-lib (v3.2.10): Loading from cache
  - Installing wikimedia/equivset (1.4.2): Loading from cache
  - Installing wikimedia/css-sanitizer (v3.0.1): Loading from cache
lcobucci/jwt suggests installing lcobucci/clock (*)
league/uri-components suggests installing jeremykendall/php-domain-parser (Public Suffix and Top Level Domain parsing implemented in PHP)
web-auth/metadata-service suggests installing web-token/jwt-key-mgmt (Mandatory for fetching Metadata Statement from distant sources)
web-auth/metadata-service suggests installing web-token/jwt-signature-algorithm-ecdsa (Mandatory for fetching Metadata Statement from distant sources)
fgrosse/phpasn1 suggests installing phpseclib/bcmath_compat (BCmath polyfill for servers where neither GMP nor BCmath is available)
ramsey/uuid suggests installing ext-uuid (Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.)
ramsey/uuid suggests installing ramsey/uuid-doctrine (Allows the use of Ramsey\Uuid\Uuid as Doctrine field type.)
ramsey/uuid suggests installing paragonie/random-lib (Provides RandomLib for use with the RandomLibAdapter)
web-auth/webauthn-lib suggests installing web-token/jwt-key-mgmt (Mandatory for the AndroidSafetyNet Attestation Statement support)
web-auth/webauthn-lib suggests installing web-token/jwt-signature-algorithm-rsa (Mandatory for the AndroidSafetyNet Attestation Statement support)
web-auth/webauthn-lib suggests installing web-token/jwt-signature-algorithm-ecdsa (Recommended for the AndroidSafetyNet Attestation Statement support)
web-auth/webauthn-lib suggests installing web-token/jwt-signature-algorithm-eddsa (Recommended for the AndroidSafetyNet Attestation Statement support)
Package phpunit/php-token-stream is abandoned, you should avoid using it. No replacement was suggested.
Writing lock file
Generating optimized autoload files
composer/package-versions-deprecated: Generating version class...
composer/package-versions-deprecated: ...done generating version class
51 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> ComposerVendorHtaccessCreator::onEvent
> ComposerVendorHtaccessCreator::onEvent

ComposerVendorHtaccessCreator::onEvent running twice at the end looks funny

Upgrade the plugin on 1.x, run update on 1.x, run update on 2.x (effectively a no-op)

$ php ../composer.phar update
> ComposerHookHandler::onPreUpdate
Loading composer repositories with package information
Updating dependencies (including require-dev)         
Package operations: 0 installs, 1 update, 0 removals
  - Removing wikimedia/composer-merge-plugin (v1.4.1)
  - Installing wikimedia/composer-merge-plugin (dev-feature/composer-v2 4195d45): Cloning 4195d45d1c from cache
Package phpunit/php-token-stream is abandoned, you should avoid using it. No replacement was suggested.
Writing lock file
Generating optimized autoload files
composer/package-versions-deprecated: Generating version class...
composer/package-versions-deprecated: ...done generating version class
51 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> ComposerVendorHtaccessCreator::onEvent
$ php ../composer.phar update
> ComposerHookHandler::onPreUpdate
Loading composer repositories with package information
Updating dependencies (including require-dev)         
Package operations: 0 installs, 0 updates, 0 removals
Package phpunit/php-token-stream is abandoned, you should avoid using it. No replacement was suggested.
Generating optimized autoload files
composer/package-versions-deprecated: Generating version class...
composer/package-versions-deprecated: ...done generating version class
51 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> ComposerVendorHtaccessCreator::onEvent
$ php ../composer-2.0.phar update
> ComposerHookHandler::onPreUpdate
Loading composer repositories with package information
Updating dependencies                                 
Lock file operations: 0 installs, 0 updates, 0 removals
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 0 installs, 0 updates, 0 removals
Package phpunit/php-token-stream is abandoned, you should avoid using it. No replacement was suggested.
Generating optimized autoload files
composer/package-versions-deprecated: Generating version class...
composer/package-versions-deprecated: ...done generating version class
51 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> ComposerVendorHtaccessCreator::onEvent
$ php ../composer-2.0.phar update
> ComposerHookHandler::onPreUpdate
Loading composer repositories with package information
Updating dependencies                                 
Nothing to modify in lock file
Installing dependencies from lock file (including require-dev)
Package operations: 0 installs, 0 updates, 0 removals
Package phpunit/php-token-stream is abandoned, you should avoid using it. No replacement was suggested.
Generating optimized autoload files
composer/package-versions-deprecated: Generating version class...
composer/package-versions-deprecated: ...done generating version class
51 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> ComposerVendorHtaccessCreator::onEvent

No vendor repo, 1.5, composer 2.x

$ php ../composer-2.0.phar update
> ComposerHookHandler::onPreUpdate
Loading composer repositories with package information
Updating dependencies                                 
Lock file operations: 121 installs, 0 updates, 0 removals
  - Locking composer/package-versions-deprecated (1.11.99.1)
  - Locking composer/semver (3.2.4)
  - Locking composer/spdx-licenses (1.5.4)
  - Locking composer/xdebug-handler (1.4.5)
  - Locking cssjanus/cssjanus (v1.3.0)
  - Locking dnoegel/php-xdg-base-dir (v0.1.1)
  - Locking doctrine/cache (1.10.2)
  - Locking doctrine/dbal (3.0.0)
  - Locking doctrine/event-manager (1.1.1)
  - Locking doctrine/instantiator (1.4.0)
  - Locking doctrine/sql-formatter (1.1.1)
  - Locking felixfbecker/advanced-json-rpc (v3.2.0)
  - Locking giorgiosironi/eris (0.10.0)
  - Locking guzzlehttp/guzzle (7.2.0)
  - Locking guzzlehttp/promises (1.4.0)
  - Locking guzzlehttp/psr7 (1.7.0)
  - Locking hamcrest/hamcrest-php (v2.0.1)
  - Locking johnkary/phpunit-speedtrap (v3.3.0)
  - Locking justinrainbow/json-schema (5.2.10)
  - Locking liuggio/statsd-php-client (v1.0.18)
  - Locking mediawiki/mediawiki-codesniffer (v35.0.0)
  - Locking mediawiki/mediawiki-phan-config (0.10.6)
  - Locking mediawiki/phan-taint-check-plugin (3.2.1)
  - Locking microsoft/tolerant-php-parser (v0.0.23)
  - Locking monolog/monolog (2.2.0)
  - Locking myclabs/deep-copy (1.10.2)
  - Locking netresearch/jsonmapper (v2.1.0)
  - Locking nikic/php-parser (v4.10.2)
  - Locking nmred/kafka-php (v0.1.5)
  - Locking oojs/oojs-ui (v0.41.1)
  - Locking pear/console_getopt (v1.4.3)
  - Locking pear/mail (v1.4.1)
  - Locking pear/mail_mime (1.10.9)
  - Locking pear/net_smtp (1.9.2)
  - Locking pear/net_socket (v1.2.2)
  - Locking pear/net_url2 (v2.2.2)
  - Locking pear/pear-core-minimal (v1.10.10)
  - Locking pear/pear_exception (v1.0.1)
  - Locking phan/phan (3.2.6)
  - Locking phar-io/manifest (2.0.1)
  - Locking phar-io/version (3.0.4)
  - Locking php-parallel-lint/php-console-color (v0.3)
  - Locking php-parallel-lint/php-console-highlighter (v0.5)
  - Locking php-parallel-lint/php-parallel-lint (v1.2.0)
  - Locking phpdocumentor/reflection-common (2.2.0)
  - Locking phpdocumentor/reflection-docblock (5.2.2)
  - Locking phpdocumentor/type-resolver (1.4.0)
  - Locking phpspec/prophecy (1.12.2)
  - Locking phpunit/php-code-coverage (7.0.14)
  - Locking phpunit/php-file-iterator (2.0.3)
  - Locking phpunit/php-text-template (1.2.1)
  - Locking phpunit/php-timer (2.1.3)
  - Locking phpunit/php-token-stream (4.0.4)
  - Locking phpunit/phpunit (8.5.14)
  - Locking pimple/pimple (v3.3.1)
  - Locking pleonasm/bloom-filter (1.0.2)
  - Locking psr/container (1.0.0)
  - Locking psr/http-client (1.0.1)
  - Locking psr/http-message (1.0.1)
  - Locking psr/log (1.1.3)
  - Locking psy/psysh (v0.10.5)
  - Locking ralouphie/getallheaders (3.0.3)
  - Locking sabre/event (5.1.2)
  - Locking sebastian/code-unit-reverse-lookup (1.0.2)
  - Locking sebastian/comparator (3.0.3)
  - Locking sebastian/diff (3.0.3)
  - Locking sebastian/environment (4.2.4)
  - Locking sebastian/exporter (3.1.3)
  - Locking sebastian/global-state (3.0.1)
  - Locking sebastian/object-enumerator (3.0.4)
  - Locking sebastian/object-reflector (1.1.2)
  - Locking sebastian/recursion-context (3.0.1)
  - Locking sebastian/resource-operations (2.0.2)
  - Locking sebastian/type (1.1.4)
  - Locking sebastian/version (2.0.1)
  - Locking seld/jsonlint (1.8.3)
  - Locking squizlabs/php_codesniffer (3.5.8)
  - Locking symfony/console (v5.2.3)
  - Locking symfony/deprecation-contracts (v2.2.0)
  - Locking symfony/polyfill-intl-grapheme (v1.22.0)
  - Locking symfony/polyfill-intl-normalizer (v1.22.0)
  - Locking symfony/polyfill-php73 (v1.22.0)
  - Locking symfony/polyfill-php80 (v1.22.0)
  - Locking symfony/service-contracts (v2.2.0)
  - Locking symfony/string (v5.2.3)
  - Locking symfony/var-dumper (v5.2.3)
  - Locking symfony/yaml (v5.2.3)
  - Locking theseer/tokenizer (1.2.0)
  - Locking webmozart/assert (1.9.1)
  - Locking wikimedia/assert (v0.5.0)
  - Locking wikimedia/at-ease (v2.0.0)
  - Locking wikimedia/avro (v1.9.0)
  - Locking wikimedia/base-convert (v2.0.1)
  - Locking wikimedia/cdb (1.4.1)
  - Locking wikimedia/cldr-plural-rule-parser (v1.0.0)
  - Locking wikimedia/common-passwords (0.2.0)
  - Locking wikimedia/composer-merge-plugin (dev-feature/composer-v2 4195d45)
  - Locking wikimedia/html-formatter (2.0.1)
  - Locking wikimedia/ip-set (2.1.0)
  - Locking wikimedia/ip-utils (3.0.1)
  - Locking wikimedia/less.php (v3.1.0)
  - Locking wikimedia/object-factory (v3.0.0)
  - Locking wikimedia/parsoid (v0.13.0-a24)
  - Locking wikimedia/php-session-serializer (v1.0.7)
  - Locking wikimedia/purtle (v1.0.7)
  - Locking wikimedia/relpath (2.1.1)
  - Locking wikimedia/remex-html (2.2.2)
  - Locking wikimedia/running-stat (v1.2.1)
  - Locking wikimedia/scoped-callback (v3.0.0)
  - Locking wikimedia/services (2.0.1)
  - Locking wikimedia/shellbox (1.0.1)
  - Locking wikimedia/testing-access-wrapper (2.0.0)
  - Locking wikimedia/timestamp (v3.0.0)
  - Locking wikimedia/utfnormal (3.0.1)
  - Locking wikimedia/wait-condition-loop (v1.0.1)
  - Locking wikimedia/wikipeg (2.0.5)
  - Locking wikimedia/wrappedstring (v3.2.0)
  - Locking wikimedia/xmp-reader (0.8.0)
  - Locking wikimedia/zest-css (1.1.4)
  - Locking wmde/hamcrest-html-matchers (v0.1.1)
  - Locking zordius/lightncandy (v1.2.5)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 121 installs, 0 updates, 0 removals
  - Syncing wikimedia/composer-merge-plugin (dev-feature/composer-v2 4195d45) into cache
  - Installing composer/package-versions-deprecated (1.11.99.1): Extracting archive
  - Installing wikimedia/composer-merge-plugin (dev-feature/composer-v2 4195d45): Cloning 4195d45d1c from cache
  - Installing cssjanus/cssjanus (v1.3.0): Extracting archive
  - Installing doctrine/event-manager (1.1.1): Extracting archive
  - Installing doctrine/cache (1.10.2): Extracting archive
  - Installing doctrine/dbal (3.0.0): Extracting archive
  - Installing doctrine/sql-formatter (1.1.1): Extracting archive
  - Installing giorgiosironi/eris (0.10.0): Extracting archive
  - Installing guzzlehttp/promises (1.4.0): Extracting archive
  - Installing ralouphie/getallheaders (3.0.3): Extracting archive
  - Installing psr/http-message (1.0.1): Extracting archive
  - Installing guzzlehttp/psr7 (1.7.0): Extracting archive
  - Installing sebastian/version (2.0.1): Extracting archive
  - Installing sebastian/type (1.1.4): Extracting archive
  - Installing sebastian/resource-operations (2.0.2): Extracting archive
  - Installing sebastian/recursion-context (3.0.1): Extracting archive
  - Installing sebastian/object-reflector (1.1.2): Extracting archive
  - Installing sebastian/object-enumerator (3.0.4): Extracting archive
  - Installing sebastian/global-state (3.0.1): Extracting archive
  - Installing sebastian/exporter (3.1.3): Extracting archive
  - Installing sebastian/environment (4.2.4): Extracting archive
  - Installing sebastian/diff (3.0.3): Extracting archive
  - Installing sebastian/comparator (3.0.3): Extracting archive
  - Installing phpunit/php-timer (2.1.3): Extracting archive
  - Installing phpunit/php-text-template (1.2.1): Extracting archive
  - Installing phpunit/php-file-iterator (2.0.3): Extracting archive
  - Installing theseer/tokenizer (1.2.0): Extracting archive
  - Installing sebastian/code-unit-reverse-lookup (1.0.2): Extracting archive
  - Installing phpunit/php-token-stream (4.0.4): Extracting archive
  - Installing phpunit/php-code-coverage (7.0.14): Extracting archive
  - Installing webmozart/assert (1.9.1): Extracting archive
  - Installing phpdocumentor/reflection-common (2.2.0): Extracting archive
  - Installing phpdocumentor/type-resolver (1.4.0): Extracting archive
  - Installing phpdocumentor/reflection-docblock (5.2.2): Extracting archive
  - Installing doctrine/instantiator (1.4.0): Extracting archive
  - Installing phpspec/prophecy (1.12.2): Extracting archive
  - Installing phar-io/version (3.0.4): Extracting archive
  - Installing phar-io/manifest (2.0.1): Extracting archive
  - Installing myclabs/deep-copy (1.10.2): Extracting archive
  - Installing phpunit/phpunit (8.5.14): Extracting archive
  - Installing johnkary/phpunit-speedtrap (v3.3.0): Extracting archive
  - Installing justinrainbow/json-schema (5.2.10): Extracting archive
  - Installing squizlabs/php_codesniffer (3.5.8): Extracting archive
  - Installing composer/spdx-licenses (1.5.4): Extracting archive
  - Installing composer/semver (3.2.4): Extracting archive
  - Installing mediawiki/mediawiki-codesniffer (v35.0.0): Extracting archive
  - Installing symfony/polyfill-php80 (v1.22.0): Extracting archive
  - Installing symfony/polyfill-intl-normalizer (v1.22.0): Extracting archive
  - Installing symfony/polyfill-intl-grapheme (v1.22.0): Extracting archive
  - Installing symfony/string (v5.2.3): Extracting archive
  - Installing psr/container (1.0.0): Extracting archive
  - Installing symfony/service-contracts (v2.2.0): Extracting archive
  - Installing symfony/polyfill-php73 (v1.22.0): Extracting archive
  - Installing symfony/console (v5.2.3): Extracting archive
  - Installing sabre/event (5.1.2): Extracting archive
  - Installing netresearch/jsonmapper (v2.1.0): Extracting archive
  - Installing microsoft/tolerant-php-parser (v0.0.23): Extracting archive
  - Installing felixfbecker/advanced-json-rpc (v3.2.0): Extracting archive
  - Installing psr/log (1.1.3): Extracting archive
  - Installing composer/xdebug-handler (1.4.5): Extracting archive
  - Installing phan/phan (3.2.6): Extracting archive
  - Installing mediawiki/phan-taint-check-plugin (3.2.1): Extracting archive
  - Installing mediawiki/mediawiki-phan-config (0.10.6): Extracting archive
  - Installing nmred/kafka-php (v0.1.5): Extracting archive
  - Installing oojs/oojs-ui (v0.41.1): Extracting archive
  - Installing pear/pear_exception (v1.0.1): Extracting archive
  - Installing pear/console_getopt (v1.4.3): Extracting archive
  - Installing pear/pear-core-minimal (v1.10.10): Extracting archive
  - Installing pear/mail (v1.4.1): Extracting archive
  - Installing pear/mail_mime (1.10.9): Extracting archive
  - Installing pear/net_socket (v1.2.2): Extracting archive
  - Installing pear/net_smtp (1.9.2): Extracting archive
  - Installing pear/net_url2 (v2.2.2): Extracting archive
  - Installing php-parallel-lint/php-console-color (v0.3): Extracting archive
  - Installing php-parallel-lint/php-console-highlighter (v0.5): Extracting archive
  - Installing php-parallel-lint/php-parallel-lint (v1.2.0): Extracting archive
  - Installing pimple/pimple (v3.3.1): Extracting archive
  - Installing psr/http-client (1.0.1): Extracting archive
  - Installing symfony/var-dumper (v5.2.3): Extracting archive
  - Installing nikic/php-parser (v4.10.2): Extracting archive
  - Installing dnoegel/php-xdg-base-dir (v0.1.1): Extracting archive
  - Installing psy/psysh (v0.10.5): Extracting archive
  - Installing seld/jsonlint (1.8.3): Extracting archive
  - Installing symfony/deprecation-contracts (v2.2.0): Extracting archive
  - Installing symfony/yaml (v5.2.3): Extracting archive
  - Installing wikimedia/avro (v1.9.0): Extracting archive
  - Installing wikimedia/base-convert (v2.0.1): Extracting archive
  - Installing wikimedia/cdb (1.4.1): Extracting archive
  - Installing wikimedia/cldr-plural-rule-parser (v1.0.0): Extracting archive
  - Installing pleonasm/bloom-filter (1.0.2): Extracting archive
  - Installing wikimedia/common-passwords (0.2.0): Extracting archive
  - Installing wikimedia/html-formatter (2.0.1): Extracting archive
  - Installing wikimedia/at-ease (v2.0.0): Extracting archive
  - Installing wikimedia/ip-set (2.1.0): Extracting archive
  - Installing wikimedia/less.php (v3.1.0): Extracting archive
  - Installing wikimedia/zest-css (1.1.4): Extracting archive
  - Installing wikimedia/wikipeg (2.0.5): Extracting archive
  - Installing wikimedia/scoped-callback (v3.0.0): Extracting archive
  - Installing wikimedia/utfnormal (3.0.1): Extracting archive
  - Installing wikimedia/remex-html (2.2.2): Extracting archive
  - Installing wikimedia/object-factory (v3.0.0): Extracting archive
  - Installing wikimedia/ip-utils (3.0.1): Extracting archive
  - Installing wikimedia/assert (v0.5.0): Extracting archive
  - Installing liuggio/statsd-php-client (v1.0.18): Extracting archive
  - Installing wikimedia/parsoid (v0.13.0-a24): Extracting archive
  - Installing wikimedia/php-session-serializer (v1.0.7): Extracting archive
  - Installing wikimedia/purtle (v1.0.7): Extracting archive
  - Installing wikimedia/relpath (2.1.1): Extracting archive
  - Installing wikimedia/running-stat (v1.2.1): Extracting archive
  - Installing wikimedia/services (2.0.1): Extracting archive
  - Installing monolog/monolog (2.2.0): Extracting archive
  - Installing guzzlehttp/guzzle (7.2.0): Extracting archive
  - Installing wikimedia/shellbox (1.0.1): Extracting archive
  - Installing wikimedia/testing-access-wrapper (2.0.0): Extracting archive
  - Installing wikimedia/wait-condition-loop (v1.0.1): Extracting archive
  - Installing wikimedia/wrappedstring (v3.2.0): Extracting archive
  - Installing wikimedia/timestamp (v3.0.0): Extracting archive
  - Installing wikimedia/xmp-reader (0.8.0): Extracting archive
  - Installing hamcrest/hamcrest-php (v2.0.1): Extracting archive
  - Installing wmde/hamcrest-html-matchers (v0.1.1): Extracting archive
  - Installing zordius/lightncandy (v1.2.5): Extracting archive
26 package suggestions were added by new dependencies, use `composer suggest` to see details.
Package phpunit/php-token-stream is abandoned, you should avoid using it. No replacement was suggested.
Generating optimized autoload files
composer/package-versions-deprecated: Generating version class...
composer/package-versions-deprecated: ...done generating version class
39 packages you are using are looking for funding.
Use the `composer fund` command to find out more!

Running composer update to apply merge settings
> ComposerHookHandler::onPreUpdate
Loading composer repositories with package information
Updating dependencies                                 
Lock file operations: 24 installs, 0 updates, 0 removals
  - Locking beberlei/assert (v3.3.0)
  - Locking brick/math (0.9.2)
  - Locking christian-riesen/base32 (1.4.0)
  - Locking defuse/php-encryption (v2.2.1)
  - Locking fgrosse/phpasn1 (v2.2.0)
  - Locking firebase/php-jwt (v5.2.0)
  - Locking jakobo/hotp-php (v2.0.0)
  - Locking lcobucci/jwt (3.4.3)
  - Locking league/event (2.2.0)
  - Locking league/oauth2-server (dev-v9.0.0-alpha a00cc3c)
  - Locking league/uri (6.4.0)
  - Locking league/uri-components (2.3.0)
  - Locking league/uri-interfaces (2.2.0)
  - Locking psr/http-factory (1.0.1)
  - Locking ramsey/collection (1.1.3)
  - Locking ramsey/uuid (4.1.1)
  - Locking spomky-labs/base64url (v2.0.4)
  - Locking spomky-labs/cbor-php (v2.0.1)
  - Locking symfony/process (v5.2.3)
  - Locking web-auth/cose-lib (v3.2.10)
  - Locking web-auth/metadata-service (v3.2.10)
  - Locking web-auth/webauthn-lib (v3.2.10)
  - Locking wikimedia/css-sanitizer (v3.0.1)
  - Locking wikimedia/equivset (1.4.2)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 24 installs, 0 updates, 0 removals
  - Syncing league/oauth2-server (dev-v9.0.0-alpha a00cc3c) into cache
  - Installing brick/math (0.9.2): Extracting archive
  - Installing christian-riesen/base32 (1.4.0): Extracting archive
  - Installing fgrosse/phpasn1 (v2.2.0): Extracting archive
  - Installing firebase/php-jwt (v5.2.0): Extracting archive
  - Installing jakobo/hotp-php (v2.0.0): Extracting archive
  - Installing league/event (2.2.0): Extracting archive
  - Installing lcobucci/jwt (3.4.3): Extracting archive
  - Installing defuse/php-encryption (v2.2.1): Extracting archive
  - Installing league/oauth2-server (dev-v9.0.0-alpha a00cc3c): Cloning a00cc3c274 from cache
  - Installing league/uri-interfaces (2.2.0): Extracting archive
  - Installing league/uri (6.4.0): Extracting archive
  - Installing league/uri-components (2.3.0): Extracting archive
  - Installing ramsey/collection (1.1.3): Extracting archive
  - Installing psr/http-factory (1.0.1): Extracting archive
  - Installing beberlei/assert (v3.3.0): Extracting archive
  - Installing web-auth/metadata-service (v3.2.10): Extracting archive
  - Installing web-auth/cose-lib (v3.2.10): Extracting archive
  - Installing symfony/process (v5.2.3): Extracting archive
  - Installing spomky-labs/cbor-php (v2.0.1): Extracting archive
  - Installing spomky-labs/base64url (v2.0.4): Extracting archive
  - Installing ramsey/uuid (4.1.1): Extracting archive
  - Installing web-auth/webauthn-lib (v3.2.10): Extracting archive
  - Installing wikimedia/css-sanitizer (v3.0.1): Extracting archive
  - Installing wikimedia/equivset (1.4.2): Extracting archive
12 package suggestions were added by new dependencies, use `composer suggest` to see details.
Package phpunit/php-token-stream is abandoned, you should avoid using it. No replacement was suggested.
Generating optimized autoload files
composer/package-versions-deprecated: Generating version class...
composer/package-versions-deprecated: ...done generating version class
51 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> ComposerVendorHtaccessCreator::onEvent
> ComposerVendorHtaccessCreator::onEvent
$ php ../composer-2.0.phar update
> ComposerHookHandler::onPreUpdate
Loading composer repositories with package information
Updating dependencies                                 
Nothing to modify in lock file
Installing dependencies from lock file (including require-dev)
Package operations: 0 installs, 0 updates, 0 removals
Package phpunit/php-token-stream is abandoned, you should avoid using it. No replacement was suggested.
Generating optimized autoload files
composer/package-versions-deprecated: Generating version class...
composer/package-versions-deprecated: ...done generating version class
51 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> ComposerVendorHtaccessCreator::onEvent

This LGTM, on the whole. The 1.x -> 2.x and plugin update in the same go not working is the only workflow that isn't great, but easily "fixed" on the local install by running composer again if necessary. The other install/upgrade/setup paths seems good.

Is there any other way we can improve that from the composer/composer plugin side? Maybe a question for composer upstream. I'm sure there won't just be MW installs where someone might upgrade the plugin (by upgrading MW, in this case; similar upgrades for other software distributions) and composer all in one go. It's obviously a bit of an edge case though

https://gerrit.wikimedia.org/r/c/mediawiki/core/+/660984 works for MediaWiki at least, and should visibly notify people that their MW install might be broken till something is remedied.

@mcaskill
Copy link
Contributor Author

mcaskill commented Feb 8, 2021

Trying to update to composer 2.0 and plugin 1.5 in one go (still needs two composer update as discussed)

With the latest commit, 4195d45, the upgrade process was working fine for me (merged dependencies get uninstalled under 1.4 but are reinstall at the end of the update to 1.5).

Can you provide me with your composer.json and composer.lock so I can test it out.

This LGTM, on the whole. The 1.x -> 2.x and plugin update in the same go not working is the only workflow that isn't great, but easily "fixed" on the local install by running composer again if necessary. The other install/upgrade/setup paths seems good.

Is there any other way we can improve that from the composer/composer plugin side? Maybe a question for composer upstream. I'm sure there won't just be MW installs where someone might upgrade the plugin (by upgrading MW, in this case; similar upgrades for other software distributions) and composer all in one go. It's obviously a bit of an edge case though

I've left the new instruction in the README regarding updating with Composer 1 first but this section might benefit from additional details.

gerrit.wikimedia.org/r/c/mediawiki/core/+/660984 works for MediaWiki at least, and should visibly notify people that their MW install might be broken till something is remedied.

👍

@reedy
Copy link
Member

reedy commented Feb 8, 2021

Trying to update to composer 2.0 and plugin 1.5 in one go (still needs two composer update as discussed)

With the latest commit, 4195d45, the upgrade process was working fine for me (merged dependencies get uninstalled under 1.4 but are reinstall at the end of the update to 1.5).

As per the output, that is the version it upgraded to. But it required a second composer run to do it

  • Upgrading wikimedia/composer-merge-plugin (v1.4.1 => dev-feature/composer-v2 4195d45)

I'll get the files together and post them.

@reedy
Copy link
Member

reedy commented Feb 8, 2021

Ok, to be fun... There's a composer.json and composer.lock, and there's a composer.local.json which then includes 6 other composer.json files from a tree. I imagine you don't want to close numerous large repos :)

So I've made a tarzip (github doesn't allow upload of tar in comments) of this... I noticed it doesn't actually install the dependancies from the other composer.json files included via composer.local.json config...

mwcomposer.zip

But confirmed, if I setup vendor on 1.x, composer update on plugin 1.5/composer 2.x it does remove everything. A second run brings them back...

$ php /var/www/wiki/mediawiki/composer-2.0.phar update
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.
Class ComposerHookHandler is not autoloadable, can not call pre-update-cmd script
Loading composer repositories with package information
Updating dependencies                                 
Lock file operations: 0 installs, 1 update, 24 removals
  - Removing beberlei/assert (v3.3.0)
  - Removing brick/math (0.9.2)
  - Removing christian-riesen/base32 (1.4.0)
  - Removing defuse/php-encryption (v2.2.1)
  - Removing fgrosse/phpasn1 (v2.2.0)
  - Removing firebase/php-jwt (v5.2.0)
  - Removing jakobo/hotp-php (v2.0.0)
  - Removing lcobucci/jwt (3.4.3)
  - Removing league/event (2.2.0)
  - Removing league/oauth2-server (dev-v9.0.0-alpha a00cc3c)
  - Removing league/uri (6.4.0)
  - Removing league/uri-components (2.3.0)
  - Removing league/uri-interfaces (2.2.0)
  - Removing psr/http-factory (1.0.1)
  - Removing ramsey/collection (1.1.3)
  - Removing ramsey/uuid (4.1.1)
  - Removing spomky-labs/base64url (v2.0.4)
  - Removing spomky-labs/cbor-php (v2.0.1)
  - Removing symfony/process (v5.2.3)
  - Removing web-auth/cose-lib (v3.2.10)
  - Removing web-auth/metadata-service (v3.2.10)
  - Removing web-auth/webauthn-lib (v3.2.10)
  - Removing wikimedia/css-sanitizer (v3.0.1)
  - Removing wikimedia/equivset (1.4.2)
  - Upgrading wikimedia/composer-merge-plugin (v1.4.1 => dev-feature/composer-v2 4195d45)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 0 installs, 1 update, 24 removals
  - Syncing wikimedia/composer-merge-plugin (dev-feature/composer-v2 4195d45) into cache
  - Removing wikimedia/equivset (1.4.2)
  - Removing wikimedia/css-sanitizer (v3.0.1)
  - Removing web-auth/webauthn-lib (v3.2.10)
  - Removing web-auth/metadata-service (v3.2.10)
  - Removing web-auth/cose-lib (v3.2.10)
  - Removing symfony/process (v5.2.3)
  - Removing spomky-labs/cbor-php (v2.0.1)
  - Removing spomky-labs/base64url (v2.0.4)
  - Removing ramsey/uuid (4.1.1)
  - Removing ramsey/collection (1.1.3)
  - Removing psr/http-factory (1.0.1)
  - Removing league/uri-interfaces (2.2.0)
  - Removing league/uri-components (2.3.0)
  - Removing league/uri (6.4.0)
  - Removing league/oauth2-server (dev-v9.0.0-alpha a00cc3c)
  - Removing league/event (2.2.0)
  - Removing lcobucci/jwt (3.4.3)
  - Removing jakobo/hotp-php (v2.0.0)
  - Removing firebase/php-jwt (v5.2.0)
  - Removing fgrosse/phpasn1 (v2.2.0)
  - Removing defuse/php-encryption (v2.2.1)
  - Removing christian-riesen/base32 (1.4.0)
  - Removing brick/math (0.9.2)
  - Removing beberlei/assert (v3.3.0)
  - Removing wikimedia/composer-merge-plugin (v1.4.1)
  - Installing wikimedia/composer-merge-plugin (dev-feature/composer-v2 4195d45): Cloning 4195d45d1c from cache
Package phpunit/php-token-stream is abandoned, you should avoid using it. No replacement was suggested.
Generating optimized autoload files
composer/package-versions-deprecated: Generating version class...
composer/package-versions-deprecated: ...done generating version class
39 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
Class ComposerVendorHtaccessCreator is not autoloadable, can not call post-update-cmd script
$ php /var/www/wiki/mediawiki/composer-2.0.phar update
Class ComposerHookHandler is not autoloadable, can not call pre-update-cmd script
Loading composer repositories with package information
Updating dependencies                                 
Lock file operations: 24 installs, 0 updates, 0 removals
  - Locking beberlei/assert (v3.3.0)
  - Locking brick/math (0.9.2)
  - Locking christian-riesen/base32 (1.4.0)
  - Locking defuse/php-encryption (v2.2.1)
  - Locking fgrosse/phpasn1 (v2.2.0)
  - Locking firebase/php-jwt (v5.2.0)
  - Locking jakobo/hotp-php (v2.0.0)
  - Locking lcobucci/jwt (3.4.3)
  - Locking league/event (2.2.0)
  - Locking league/oauth2-server (dev-v9.0.0-alpha a00cc3c)
  - Locking league/uri (6.4.0)
  - Locking league/uri-components (2.3.0)
  - Locking league/uri-interfaces (2.2.0)
  - Locking psr/http-factory (1.0.1)
  - Locking ramsey/collection (1.1.3)
  - Locking ramsey/uuid (4.1.1)
  - Locking spomky-labs/base64url (v2.0.4)
  - Locking spomky-labs/cbor-php (v2.0.1)
  - Locking symfony/process (v5.2.3)
  - Locking web-auth/cose-lib (v3.2.10)
  - Locking web-auth/metadata-service (v3.2.10)
  - Locking web-auth/webauthn-lib (v3.2.10)
  - Locking wikimedia/css-sanitizer (v3.0.1)
  - Locking wikimedia/equivset (1.4.2)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 24 installs, 0 updates, 0 removals
  - Syncing league/oauth2-server (dev-v9.0.0-alpha a00cc3c) into cache
  - Installing brick/math (0.9.2): Extracting archive
  - Installing christian-riesen/base32 (1.4.0): Extracting archive
  - Installing fgrosse/phpasn1 (v2.2.0): Extracting archive
  - Installing firebase/php-jwt (v5.2.0): Extracting archive
  - Installing jakobo/hotp-php (v2.0.0): Extracting archive
  - Installing league/event (2.2.0): Extracting archive
  - Installing lcobucci/jwt (3.4.3): Extracting archive
  - Installing defuse/php-encryption (v2.2.1): Extracting archive
  - Installing league/oauth2-server (dev-v9.0.0-alpha a00cc3c): Cloning a00cc3c274 from cache
  - Installing league/uri-interfaces (2.2.0): Extracting archive
  - Installing league/uri (6.4.0): Extracting archive
  - Installing league/uri-components (2.3.0): Extracting archive
  - Installing ramsey/collection (1.1.3): Extracting archive
  - Installing psr/http-factory (1.0.1): Extracting archive
  - Installing beberlei/assert (v3.3.0): Extracting archive
  - Installing web-auth/metadata-service (v3.2.10): Extracting archive
  - Installing web-auth/cose-lib (v3.2.10): Extracting archive
  - Installing symfony/process (v5.2.3): Extracting archive
  - Installing spomky-labs/cbor-php (v2.0.1): Extracting archive
  - Installing spomky-labs/base64url (v2.0.4): Extracting archive
  - Installing ramsey/uuid (4.1.1): Extracting archive
  - Installing web-auth/webauthn-lib (v3.2.10): Extracting archive
  - Installing wikimedia/css-sanitizer (v3.0.1): Extracting archive
  - Installing wikimedia/equivset (1.4.2): Extracting archive
12 package suggestions were added by new dependencies, use `composer suggest` to see details.
Package phpunit/php-token-stream is abandoned, you should avoid using it. No replacement was suggested.
Generating optimized autoload files
composer/package-versions-deprecated: Generating version class...
composer/package-versions-deprecated: ...done generating version class
51 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
Class ComposerVendorHtaccessCreator is not autoloadable, can not call post-update-cmd script

@prudloff-insite
Copy link

@mcaskill I tried 4195d45.
It seems to work correctly with Composer 2. But with Composer 1, it crashes with this error:

PHP Fatal error:  Uncaught Error: Call to undefined method Composer\Installer::setUpdateAllowList() in /mnt/data/workspace/drupal/vendor/wikimedia/composer-merge-plugin/src/MergePlugin.php:374
Stack trace:
#0 [internal function]: Wikimedia\Composer\MergePlugin->onPostInstallOrUpdate()
#1 /usr/share/php/Composer/EventDispatcher/EventDispatcher.php(164): call_user_func()
#2 /usr/share/php/Composer/EventDispatcher/EventDispatcher.php(96): Composer\EventDispatcher\EventDispatcher->doDispatch()
#3 /usr/share/php/Composer/Installer.php(338): Composer\EventDispatcher\EventDispatcher->dispatchScript()
#4 /usr/share/php/Composer/Command/InstallCommand.php(122): Composer\Installer->run()
#5 /usr/share/php/Symfony/Component/Console/Command/Command.php(255): Composer\Command\InstallCommand->execute()
#6 /usr/share/php/Symfony/Component/Console/Application.php(934): Symfony\Component\Console\Command\Command->run()
#7 /usr/share/php/Symfony/Component/Console/Application.php(273): Symfony\Component\Console\Application->doRunCommand()
#8 /usr in /mnt/data/workspace/drupal/vendor/wikimedia/composer-merge-plugin/src/MergePlugin.php on line 374

@mcaskill
Copy link
Contributor Author

mcaskill commented Feb 8, 2021

Oh, yeah, I should take into account that Installer::setUpdateAllowList() was only added in Composer 1.10.8 replace Installer::setUpdateWhitelist(). I'll fix that.

Fixes backwards compatibility with versions older than Composer 1.10.8.

Amends 4195d45
@mcaskill
Copy link
Contributor Author

mcaskill commented Feb 9, 2021

This morning while updating a client project, I stumbled upon the same bug as @AntoninSlejska and @chrissnyder2337:

Fatal error: Uncaught Error: Call to undefined method Wikimedia\Composer\Merge\ExtraPackage::getMergedRequirements() in phar:///usr/local/bin/composer/src/Composer/Plugin/PluginManager.php(220) : eval()'d code:287
Stack trace:
#0 phar:///usr/local/bin/composer/src/Composer/Plugin/PluginManager.php(220) : eval()'d code(254): Wikimedia\Composer\MergePlugin_composer_tmp0->mergeFile(Object(Composer\Package\RootPackage), 'composer.local....')
#1 phar:///usr/local/bin/composer/src/Composer/Plugin/PluginManager.php(220) : eval()'d code(215): Wikimedia\Composer\MergePlugin_composer_tmp0->mergeFiles(Array, false)
#2 [internal function]: Wikimedia\Composer\MergePlugin_composer_tmp0->onInstallUpdateOrDump(Object(Composer\Script\Event))
#3 phar:///usr/local/bin/composer/src/Composer/EventDispatcher/EventDispatcher.php(172): call_user_func(Array, Object(Composer\Script\Event))
#4 phar:///usr/local/bin/composer/src/Composer/EventDispatcher/EventDispatcher.php(101): Composer\EventDispatcher\EventDispatcher->doDispatch(Object(Composer\Sc in phar:///usr/local/bin/composer/src/Composer/Plugin/PluginManager.php(220) : eval()'d code on line 287

When it occurred, the plugin was being updated from a8c5a89 (pre-getMergedRequirements()) to b8b8cb4. After this error was raised, I consulted the vendor directory and it contained the correct copy of files.

@Seldaek Sorry to bother you. Do you have any idea why there would be a discrepancy?

Maybe it has something to do when composer update is initially executed, the plugin at a8c5a89 is loaded into memory, packages are updated including the plugin (now at b8b8cb4) which is then loaded into memory causing a conflict.

@Seldaek
Copy link

Seldaek commented Feb 10, 2021

Yeah Composer makes an effort to load the new version of the plugin class after an upgrade, by renaming the class in memory and loading that, but if the plugin has dependencies that are already loaded those do not get updated and there you may get trouble. This works well for plugins which are in a self-contained class. See https://github.com/composer/composer/blob/40095b20dc58772b7b630e1ca41f024fda7eae44/src/Composer/Plugin/PluginManager.php#L204-L223 for details but this won't really help you here.

The solution would be to make the new code check for method existence I guess and abort if it's missing, to make the upgrade smoother. Or put all the relevant/required logic in that one class..

@tstarling
Copy link
Contributor

It looks like this class renaming issue has been there since before composer 2.0, so there's no obvious need to deal with it in the same PR.

@mcaskill
Copy link
Contributor Author

I'm thinking of adding a method exists check on ExtraPackage::getMergedRequirements() from MergePlugin and display a message to that effect.

@tstarling
Copy link
Contributor

I was thinking we could change the namespace to Wikimedia\Composer\Merge2. We'd increment the namespace version number every time there is a similar breaking change.

Copy link
Contributor

@tstarling tstarling left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've finished reviewing this. If @mcaskill is happy with it being merged now, then I'll merge it. I don't think it's blocked on a fix for the class renaming issue. If a fix for that appears in a separate PR then we can still include it in 1.5.0.

@tstarling tstarling merged commit a674d4b into wikimedia:master Feb 12, 2021
@mcaskill
Copy link
Contributor Author

mcaskill commented Feb 12, 2021

Thanks for merging.

I'm not satisfied with the last outstanding issue of the outdated ExtraPackage.
I'm surprised we had not stumbled upon the issue sooner with the addition of PluginState::isComposer1() that is used in most classes.

We could introduce a similar class-swapping mechanism as Composer's PluginManager or introducing a versioned namespace to the Merge Plugin.

Instead of Wikimedia\Composer\Merge2, maybe Wikimedia\Composer\Merge\V2 and move MergePlugin into it as well?

@reedy
Copy link
Member

reedy commented Feb 12, 2021

Sounds reasonable to me. PR welcome ;)

It's probably easiest to just start a PR (if you're willing to work on this issue too), and then it's a bit easier to make a decision about naming when we have a more concrete example. Renaming/moving things around is easy enough while it's still WIP

@mcaskill
Copy link
Contributor Author

I might not be able to start work on this over the weekend. If someone else jumps on the occasion, I am available to contribute to that pull request.

This is indeed turning into a major update (1.4 → 2.0) rather than a minor update (1.4 → 1.5).

@reedy
Copy link
Member

reedy commented Feb 12, 2021

I don't think needing to bump the major version is a particular issue. There's some that would argue (and some that wouldn't!) that bumping the required PHP version alone does that.

@mcaskill
Copy link
Contributor Author

Of course. I'm bringing this up in relation to @tstarling proposing to rename the namespace to force Composer to load the new classes once it boots the new MergePlugin class.

@hexmode
Copy link

hexmode commented Feb 12, 2021

This is indeed turning into a major update (1.4 → 2.0) rather than a minor update (1.4 → 1.5).

Agreed.

Since this is distributed on Packagist and packagist.org states under Managing package versions: "The use of Semantic Versioning is strongly encouraged", it makes sense to use semantic versioning.

SemVer says "increment the... MAJOR version when you make incompatible API changes" and since you need to use composer2 to use this update, bumping the major version makes sense.

@reedy
Copy link
Member

reedy commented Feb 12, 2021

Since this is distributed on Packagist and packagist.org states under Managing package versions: "The use of Semantic Versioning is strongly encouraged", it makes sense to use semantic versioning.

SemVer says "increment the... MAJOR version when you make incompatible API changes" and since you need to use composer2 to use this update, bumping the major version makes sense.

Unfortunately, many projects don't see it that way.

@hexmode
Copy link

hexmode commented Feb 13, 2021

Unfortunately, many projects don't see it that way.

Two of the links you provide talk about specific situations, but don't really make broader recommendations relevant to this situation. The first link is about the problems caused when including composer.lock files. We're talking about version numbers.

The second, Composer, semver, and underlying dependency changes, does offer some good insights into what we might do here. The post makes an attempt at offering some best practices.

The third link ostensibly refutes the second link, but is really just talking about some of the problems they ran into. I think this sentence is telling:

So who's to blame? Let's point the finger at myself first: we should have updated league/commonmark sooner.

This is another best practice, keep your dependencies up to date (which is kind of what this whole "Add support for Composer v2" is about).

Best practices (what the second post offered) are not a panacea. Composer isn't perfect, but if used with best practices, suffering is reduced.

But, with all this in mind and after reading the "Composer, semver, and underlying dependency changes" link, I think only a minor version bump is appropriate.

@Seldaek
Copy link

Seldaek commented Feb 13, 2021

FWIW I tend to agree that bumping dependencies is not a BC break. As long as your API does not change, it's not a BC break. Your dependencies are in theory not part of the API, they're an implementation detail the consumers should not have to know about.

That said, with PHP version I can see that this being a dependency of all php code, including your consumers, it can make sense to treat it as a BC break too. Projects like Symfony for example do this and I find it reasonable too, it's much easier to communicate to users for starters, and it's part of their BC promise, which is an extension of semver.

The main benefit I see of bumping to 2.0 here would be that it leaves the door open to releasing a new 1.5 for new features for composer 1, but if you don't see yourselves doing that then IMO leaving it at 1.5 now makes more sense, and it simplifies the upgrade path as people requiring the merge plugin with ^1 won't have to do anything to benefit from the Composer 2 support.

@mcaskill
Copy link
Contributor Author

mcaskill commented Feb 13, 2021

I think people have lost track of why the "1.5 vs 2.0" proposal.

Me and @tstarling are referring to renaming the plugin's PHP namespace to prevent MergePlugin 1.5/2.0 from using the, potentially already autoloaded, ExtraPackage (getMergedRequirements()) and PluginState (isComposer1()) from 1.4 since I've introduced breaking changes.

We could introduce a similar class-swapping mechanism as Composer's PluginManager or introducing a versioned namespace to the Merge Plugin.

Instead of Wikimedia\Composer\Merge2, maybe Wikimedia\Composer\Merge\V2 […]

Such namespacing implies we bump the package's version to 2.0.0 because how you namespace 1.5.x.

Alternatively, maybe we can rename ExtraPackage (to Package) and PluginState (?).

@mcaskill mcaskill mentioned this pull request Feb 14, 2021
XedinUnknown added a commit to Dhii/php-project that referenced this pull request Apr 27, 2024
This is OK now, because before Composer v1 support was required for wikimedia/composer-merge-plugin - and now the plugin supports Composer v2.

wikimedia/composer-merge-plugin#189
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet