Problem/Motivation

Upgrading drupal/core-composer-scaffold from any 8.8.x version to any 8.9.x version causes a PHP fatal error.

Example:

$ composer create-project drupal/recommended-project:8.8.4
$ cd recommended-project
$ composer require drupal/core-composer-scaffold:8.9.x-dev
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 0 installs, 1 update, 0 removals
  - Removing drupal/core-composer-scaffold (8.8.4)
  - Installing drupal/core-composer-scaffold (8.9.x-dev 16a4227): Cloning 16a4227460 from cache
Package zendframework/zend-diactoros is abandoned, you should avoid using it. Use laminas/laminas-diactoros instead.
Package zendframework/zend-escaper is abandoned, you should avoid using it. Use laminas/laminas-escaper instead.
Package zendframework/zend-feed is abandoned, you should avoid using it. Use laminas/laminas-feed instead.
Package zendframework/zend-stdlib is abandoned, you should avoid using it. Use laminas/laminas-stdlib instead.
Writing lock file
Generating autoload files
Deprecation Notice: Non-static method Drupal\Composer\Plugin\Scaffold\Operations\ScaffoldFileCollection::process() should not be called statically in /Users/ganderson/tmp/drupal-upgrade-test/recommended-project/vendor/drupal/core-composer-scaffold/Handler.php:167
PHP Fatal error:  Uncaught TypeError: Argument 1 passed to Drupal\Composer\Plugin\Scaffold\Operations\ScaffoldFileCollection::process() must implement interface Composer\IO\IOInterface, instance of Drupal\Composer\Plugin\Scaffold\Operations\ScaffoldFileCollection given, called in /Users/ganderson/tmp/drupal-upgrade-test/recommended-project/vendor/drupal/core-composer-scaffold/Handler.php on line 167 and defined in /Users/ganderson/tmp/drupal-upgrade-test/recommended-project/vendor/drupal/core-composer-scaffold/Operations/ScaffoldFileCollection.php:133
Stack trace:
#0 /Users/ganderson/tmp/drupal-upgrade-test/recommended-project/vendor/drupal/core-composer-scaffold/Handler.php(167): Drupal\Composer\Plugin\Scaffold\Operations\ScaffoldFileCollection::process(Object(Drupal\Composer\Plugin\Scaffold\Operations\ScaffoldFileCollection), Object(Composer\IO\ConsoleIO), Object(Drupal\Composer\Plugin\Scaffold\ScaffoldOptions))
#1 phar:///Users/ganderson/bin/composer/src/Composer/Plugin/PluginManager.php(196) : eval()'d code(70): Drupal\Com in /Users/ganderson/tmp/drupal-upgrade-test/recommended-project/vendor/drupal/core-composer-scaffold/Operations/ScaffoldFileCollection.php on line 133

Once there is a stable release of Drupal 8.9.0 / 9.0.0, the same error will happen when using composer update to upgrade Drupal.

The Drupal 9 upgrade path is supposed to be very easy; encountering a PHP fatal error during the process would cause a lot of confusion and dissatisfaction with the upgrade process.

Proposed resolution

This upgrade bug was fixed by #3104922: Guard against changes to Scaffold Plugin that might cause upgrade problems ; however, that patch was not back-ported to the 8.8.x branch. That omission should not have been cause for any trouble (c.f. #35), EXCEPT for the fact that the test that should have guarded against changes that caused problems did not work correctly (failures passed instead of being flagged).

The fix, therefore, is twofold:

  1. Fix the test so that it correctly fails when there is a problem in the upgrade path.
  2. Fix the problem in the upgrade path that was committed to 8.9.x / 9.0.x.

Remaining tasks

  1. Write a failing test
  2. Fix the failing test

User interface changes

None

API changes

None

Data model changes

None

Release notes snippet

A PHP fatal error that was triggered when upgrading the Core Composer Scaffold plugin has been fixed.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

greg.1.anderson created an issue. See original summary.

greg.1.anderson’s picture

greg.1.anderson’s picture

Status: Active » Needs review

Setting to "needs review" to run the failing test.

greg.1.anderson’s picture

Here is a patch that fixes the test from #2.

greg.1.anderson’s picture

Made my patches against 9.0.x instead of 8.9.x. Re-queued on the correct branch.

xjm’s picture

Issue tags: +beta target

Oy.

greg.1.anderson’s picture

Here's a failing test that should fail the correct way.

greg.1.anderson’s picture

Here's the fix. Interdiff is the same as #7.

greg.1.anderson’s picture

The failing test in #7 now matches the symptoms reported in the IS, and the patch in #8 is green, so this is ready for review now.

jungle’s picture

  1. Reproduced the error in IS mannully on my local with the steps below:
    $ composer create-project drupal/recommended-project:8.8.4 -vvv
    $ cd recommended-project/
    $ composer require drupal/core-composer-scaffold:8.9.x-dev -vvv
    
  2. Furthermore, confirmed that composer update does not work as expected on my local as well.
    $ composer create-project drupal/recommended-project:8.8.4 recommended-project2 -vvv
    $ cd recommended-project2/
    $ composer update -vvv
    

    Excpected version of drupal/core after running the commands above, is 8.8.5, but the actual version is 8.9.x-dev

  3. No idea how to test the patch manually, But as the test-only patch in #7 reproduced the error exactly descripted in IS. and the patch in #8 fixed the error. I'd give a general +1 to the patch,
  4. A tip for backporting the patch to 8.9.x: in order to get assertStringContains() working, the trait PhpunitCompatibilityTrait should be used in ScaffoldUpgradeTest.
catch’s picture

+++ b/composer/Plugin/Scaffold/Operations/ScaffoldFileCollection.php
@@ -141,6 +141,33 @@ public function process(IOInterface $io, ScaffoldOptions $scaffold_options) {
+   *
+   * @deprecated. Only called when upgrading from the Core Composer Scaffold
+   *   plugin version 8.8.x.; remove in Drupal 9.1.x.
+   */

We should mark this @internal, we can't really deprecate it because it still has to be called and there's no way remove those calls until the new release. It will also need to be retained until Drupal 10 (i.e. remove in Drupal 10.0.0) - since we theoretically allow updates from Drupal 8.8 to Drupal 9.LAST.

The 8.9-dev issue that @jungle saw has its own issue at #3134648: [backport, needs scheduling] Don't pin the composer/installers version in drupal/core-recommended.

greg.1.anderson’s picture

I think that it is more correct to call this method @deprecated rather than @internal. The static process method should never be called in any 8.9.x or 9.x+ version of Drupal. The @deprecated tag lets you know that it should not be used. This method is not deprecated in Drupal 8.8.x; due to a bug, when the 8.8.x code calls the static process method, it might first load the 8.9.x or 9.0.x version of the class. This is the only time that the static function might be called.

If we tagged this method @internal, that would imply that it is okay to call the method from within other parts of the Core Composer Scaffold plugin, which is not correct.

I updated the comment to be more clear about the situation, and to update the advise to remove in Drupal 10 rather than in Drupal 9.1. I also made an 8.9.x version of the patch following the advice in #10.

Kristen Pol’s picture

Thanks for the update. Only looked at the interdiff and noticed a tiny nitpick:

+++ b/composer/Plugin/Scaffold/Operations/ScaffoldFileCollection.php
@@ -154,8 +154,9 @@ public function processScaffoldFiles(IOInterface $io, ScaffoldOptions $scaffold_
+   *   version 8.8.x. due to a bug in the plugin and handler classes. Do not use

Nitpick in interdiff:

Change "8.8.x." to "8.8.x" (remove period at end).

greg.1.anderson’s picture

Kristen Pol’s picture

Confirmed that #14 fixes the nitpick in #13 but leaving as "Needs review" as I don't understand the patch well enough to review better. :)

longwave’s picture

+++ b/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ScaffoldUpgradeTest.php
@@ -66,13 +67,25 @@ public function testScaffoldUpgrade() {
+    // Using 'mustExec' was giving a strange binary string here.
+    exec("composer --working-dir=$sut require drupal/core-composer-scaffold:$testVersion 2>&1", $output, $status);

Does the --no-ansi switch to composer require help? This should remove the colour encoding which might be the source of the binary string.

alexpott’s picture

The binary string thing happens because PHPUnit does

            // Match for most non printable chars somewhat taking multibyte chars into account
            if (\preg_match('/[^\x09-\x0d\x1b\x20-\xff]/', $value)) {
                return 'Binary String: 0x' . \bin2hex($value);
            }

in \SebastianBergmann\Exporter\Exporter::recursiveExport(). See https://github.com/sebastianbergmann/phpunit/issues/736 for more.

longwave’s picture

Yeah, and I think --no-ansi should remove those non printable characters from the output - we use it in many other composer command lines in build tests.

greg.1.anderson’s picture

Thanks, @longwave; that is, in fact, cleaner.

longwave’s picture

Status: Needs review » Reviewed & tested by the community

Discussed with @greg.1.anderson on Slack after trying to manually reproduce; the only way to do so is have a git repository containing the updated plugin, as you have to remove the old directory from vendor first before switching to a path-based repository, and then the bug isn't triggered. Then I realised that this is exactly what the test does, and that passes, so the 9.0.x patch is RTBC. We could do with an 8.9.x patch to match though, as the one in #14 needs updating to include the --no-ansi switch.

greg.1.anderson’s picture

Here's the 8.9.x version of #19. Interdiff for 14-to-21 is the same as 12-to-19.

  • catch committed 90af0a6 on 9.1.x
    Issue #3134606 by greg.1.anderson, longwave, Kristen Pol, catch, jungle...

  • catch committed 680a03b on 9.0.x
    Issue #3134606 by greg.1.anderson, longwave, Kristen Pol, catch, jungle...
catch’s picture

Title: PHP Fatal error in 8.9.x / 9.0.x upgrade path » [backport] PHP Fatal error in 8.9.x / 9.0.x upgrade path
Version: 9.0.x-dev » 8.9.x-dev

Committed/pushed to 9.1.x and cherry-picked to 9.0.x

The 8.9.x backport is still with DrupalCI, so waiting for green there.

  • catch committed 0423e3b on 8.9.x
    Issue #3134606 by greg.1.anderson, longwave, catch, Kristen Pol, jungle...
catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed 0423e3b and pushed to 8.9.x. Thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.