Allow pre-drupal-scaffold-cmd event to modify composer object/scaffold options

Created on 13 November 2020, about 4 years ago
Updated 7 April 2024, 9 months ago

Problem/Motivation

Currently, the scaffold command in the drupal/core-composer-scaffold library doesn't give context to the event to allow making modifications before scaffold, which seems limited and makes the pre-scaffold event fairly useless.

With a slight modification to the library, it would allow scripts to dynamically modify the files and locations to be scaffolded.

Steps to reproduce

Fire off a script in pre-drupal-scaffold-cmd and attempt to make changes to the composer object. Depending on how it's written, it will either pass an EventDispatcher\Event object, which doesn't have access to the composer object, or it will pass a ScriptEvent, which even with access to the composer object, the changes aren't relayed back to the scaffold event since the options and packages are initialized before the scaffold event runs.

Proposed resolution

Place the event dispatcher first in the scaffold method, use dispatchScript() instead of dispatch() to pass the composer object to the event, and then reinitialize the ManageOptions and AllowedPackages Objects.

API changes

The only real API change would be that we're passing in an Composer\Script\Event object instead of a Composer\EventDispatcher\Event object. But since the Script\Event object extends the EventDispatcher\Event object, it shouldn't be a breaking change.

Data model changes

Release notes snippet

✨ Feature request
Status

Needs work

Version

11.0 πŸ”₯

Component
ComposerΒ  β†’

Last updated 8 days ago

No maintainer
Created by

πŸ‡ΊπŸ‡ΈUnited States grathbone

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • The Needs Review Queue Bot β†’ tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

    Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.

    Consult the Drupal Contributor Guide β†’ to find step-by-step guides for working with issues.

  • πŸ‡¦πŸ‡ΊAustralia alex.skrypnyk Melbourne

    I may be mistaken, but it looks like that the purpose of `pre-drupal-scaffold-cmd` is to manipulate files rather than configuration.
    If I am mistaken and there is no such limitation, than this issue will indeed allow to do some very useful alterations like declaring scaffold file-mapping on behalf of other packages.

    The proposed resolution

    Place the event dispatcher first in the scaffold method, use dispatchScript() instead of dispatch() to pass the composer object to the event, and then reinitialize the ManageOptions and AllowedPackages Objects.

    possess a security risk though: reinitializing of ManageOptions and, more risky, AllowedPackages will allow other packages to inject allowing of 3rd party packages to be scaffolded. Such allow list should not be alterable and should be controlled only from the root package composer.json.

    Instead, the order of operations should be preserved as-is and only the dispatched event should be changed to use dispatchScript() to pass the Composer context to the event handlers. Similar request has already been lodged in https://www.drupal.org/project/drupal/issues/3266160 πŸ› Composer Scaffold plugin calls dispatch() instead of dispatchScript() Needs work

    Than, we can do things like:

    // Code in `myorg/my-skeleton-tooling` package's Composer plugin.
    
    public static function getSubscribedEvents() {
      return [
        Handler::PRE_DRUPAL_SCAFFOLD_CMD => 'preDrupalScaffoldCmd',
      ];
    }
    
    public function preDrupalScaffoldCmd(\Composer\Script\Event $event) {
        $packages = $event->getComposer()
          ->getRepositoryManager()
          ->getLocalRepository()
          ->getPackages();
    
        foreach ($packages as $package) {
          if ($package->getName() === 'myorg/my-skeleton') {
            $extra = $package->getExtra();
            // Inject files on behalf of 'my-skeleton-package' package.
            $extra['drupal-scaffold']['file-mapping']['[project-root]/myfile1.txt'] = 'myfile1.txt';
            $package->setExtra($extra);
          }
        }
      }
    

    This powerful functionality allows to keep custom project skeletons, that want to distribute and update their files using the core Scaffold plugin, to manage the list of their files in the additional plugin rather than polluting the composer.json with, what could be, 100s of scaffold file mappings.

    Note that the current event dispatcher initialisation process has a bug, where discovered plugins are not "remembered", tracked in https://www.drupal.org/project/drupal/issues/3438034 πŸ› Composer Scaffold plugin event listeners do not receive event dispatch" is mostly correct but could be clearer. Here’s a revised version for better clarity: "Event listeners in the Composer Scaffold plugin do not receive event dispatches Active . The requested change to use dispatchScript() instead of dispatch() will only work once that issue is resolved.

    Before any work can be done here, we need core maintainers to confirm that this approach does not violate initial intent of the plugin.

Production build 0.71.5 2024