Problem/Motivation

We're still following through on #1826054: [Meta] Expose Drupal Components outside of Drupal

And we need to be able to test our components independent of Drupal core.

As a very small first step, we need to allow each component to specify it's PSR-4 autoload and autoload-dev sections per composer.json file.

We want each component to define its own namespace.

Since we're merging all of the components' composer.json files during composer install time, their autoload and autoload-dev sections can be used to generate the PSR-4 mappings for each individual component.

Currently, core/composer.json forces all components to be PSR-4 namespaces, which disallows moving source files into subdirectories.

This will open the door to moving the source files of those components into a src/ directory, and also moving the components' test files into a tests/ directory.

We don't actually need to move source files into src/ directories.

Proposed resolution

Remaining tasks

None

User interface changes

None

API changes

None

Data model changes

None

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Mile23 created an issue. See original summary.

Mile23’s picture

Status: Active » Needs review
FileSize
3.22 KB

Here's a POC. It only moves Annotation to a src/ directory, but illustrates that autoloading already works because each component already specifies autoload. :-)

I hadn't remembered that for some reason, so this issue could probably use some re-scoping.

Mile23’s picture

Issue summary: View changes
Mile23’s picture

Added #2943856: [meta] Reorganize Components so they are testable in isolation, mostly so I could note that we need to move Transliteration/src/data to tests/data when the time comes, and change the tests to use it.

This is all the components moved to src/ with updated composer.json. Also updating core/composer.json to reflect the components' new-found self-naming agency.

Status: Needs review » Needs work

The last submitted patch, 4: 2943842_4.patch, failed testing. View results

Mile23’s picture

Let's hurry up and get rid of PHP 5 please. :-)

Mile23’s picture

Status: Needs work » Needs review
alexpott’s picture

I'm not sure this is truly necessary... it's not what Symfony does. They do
One problem is that the regular runtime autoloader should not be able to autoload tests so each composer.json is going to need something like

    "autoload": {
        "exclude-from-classmap": [
            "/Tests/"
        ]
   },

The one bit of fun is that our test infra is rather bizarre in that it autoloads tests.... however I think I have a solution for that. See https://www.drupal.org/project/drupal/issues/2943856

alexpott’s picture

I actually think we could merge this issue into the https://www.drupal.org/project/drupal/issues/2943856 rather than do it in two separate steps if we don't have to move all the code into src.

alexpott’s picture

Hmmm... but actually maybe the test move issue should be a meta and we should move each component separately as we should add a PHPUnit.xml.dist to each component and change or maybe removing the TESTING.txt since it is probably overkill once the phpunit.xml.dist is in place.

So let's sort out the autoloader / component composer.json's here. Slightly different tack so no interdiff. It is basically #6 without the file moves and adding ignoring of any Tests folders (which are yet to exist but that does not matter).

Mile23’s picture

One problem is that the regular runtime autoloader should not be able to autoload tests

Correct. :-)

When we remove the Drupal\Components\ namespace from core/composer.json's PSR-4 section, that lets the components define their own PSR-4 namespace.

Try it: Apply the patch in #6 (or really #10, either way). Remove an autoload section from one of the component's composer.json. Do a composer dumpautoload. Then run the tests: ./vendor/bin/phpunit -c core/ core/tests/Drupal/Tests/Component/ You'll see that the autoloading for that component isn't available.

I actually think we could merge this issue into #2943856: [meta] Reorganize Components so they are testable in isolation

I think we want the tests to remain where they are so we can be consistent with the move here, and then move the tests as a separate step.

+++ b/core/lib/Drupal/Component/Annotation/composer.json
@@ -15,6 +15,9 @@
       "Drupal\\Component\\Annotation\\": ""
...
+    "exclude-from-classmap": [
+      "/Tests/"

Given that each component can define its own PSR-4, we can leave the classes at the top level directory, or put the source in a src/ directory. If we put it in a src/ directory, we don't have to exclude-from-classmap for tests later on.

alexpott’s picture

@Mile23 but we're already inside core's lib directory. Let's follow Symfony's lead and not add extra unnecessary subdirectories. Also not moving the code is just less change (that is not necessary).

Mile23’s picture

We are inside core/lib, but core/composer.json says this:

    "autoload": {
        "psr-4": {
            "Drupal\\Core\\": "lib/Drupal/Core",
            "Drupal\\Component\\": "lib/Drupal/Component",
            "Drupal\\Driver\\": "../drivers/lib/Drupal/Driver"
        },

So the only PSR-4 autoloading for core is lib/Drupal/Core/ after we remove the entry for lib/Drupal/Component.

Either way is fine, just less hassle later with src/ if we're going to move tests around, since we'll be able to rely on the tests in this issue.

Mile23’s picture

Status: Needs review » Needs work
+++ b/core/composer.json
@@ -192,13 +192,10 @@
-            "lib/Drupal/Component/Utility/Timer.php",
-            "lib/Drupal/Component/Utility/Unicode.php",

+++ b/core/lib/Drupal/Component/Annotation/composer.json
@@ -15,6 +15,9 @@
+    "exclude-from-classmap": [
+      "/Tests/"

If we're not going to use src/ then we don't really need to add an exclude for a non-existent directory. In that case we don't really need to change any of the composer.json files other than core.

The only change we might need to a component compser.json would be to add Timer and Unicode to the classmap in Utility's composer.json if we think that's worth the performance improvement.

alexpott’s picture

Fair enough we can add the tests to the exclude when we move them. The files were first hard coded to the class loader in #2253593: Stop classloader searching filesystem for classes before drupal_classloader() is called - i'm not sure we even need to change that here. So this patch becomes a 1 liner :)

alexpott’s picture

Mile23’s picture

Status: Needs review » Reviewed & tested by the community

I'd give a little pushback on removing the classmap lines from core and putting them in Utility, but it's not a problem until it becomes one at some point. :-)

alexpott’s picture

Issue summary: View changes

Updated the issue summary to be inline with current patch.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 16: 2943842-16.patch, failed testing. View results

alexpott’s picture

Status: Needs work » Reviewed & tested by the community

Testbot had a hiccup re-rtbcing

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 16: 2943842-16.patch, failed testing. View results

Mile23’s picture

Mile23’s picture

Status: Needs work » Reviewed & tested by the community

Re-setting RTBC now that the permission issue is fixed.

Anonymous’s picture

(Edit: not that tab, sorry)

neclimdul’s picture

I don't see any comment on why the patch actually works. Is is because of the merge-plugin entries in core's composer.json?

I'm curious how this will affect composer install projects like https://github.com/drupal-composer but I'm not sure how to give it a solid test without committing so assuming the answer to the above question is yes I agree this is a solid improvement.

alexpott’s picture

Yep it's because of the merge-plugin entries in core's composer.json - all of this:

        "merge-plugin": {
            "require": [
                "core/lib/Drupal/Component/Annotation/composer.json",
                "core/lib/Drupal/Component/Assertion/composer.json",
                "core/lib/Drupal/Component/Bridge/composer.json",
                "core/lib/Drupal/Component/ClassFinder/composer.json",
                "core/lib/Drupal/Component/Datetime/composer.json",
                "core/lib/Drupal/Component/DependencyInjection/composer.json",
                "core/lib/Drupal/Component/Diff/composer.json",
                "core/lib/Drupal/Component/Discovery/composer.json",
                "core/lib/Drupal/Component/EventDispatcher/composer.json",
                "core/lib/Drupal/Component/FileCache/composer.json",
                "core/lib/Drupal/Component/FileSystem/composer.json",
                "core/lib/Drupal/Component/Gettext/composer.json",
                "core/lib/Drupal/Component/Graph/composer.json",
                "core/lib/Drupal/Component/HttpFoundation/composer.json",
                "core/lib/Drupal/Component/PhpStorage/composer.json",
                "core/lib/Drupal/Component/Plugin/composer.json",
                "core/lib/Drupal/Component/ProxyBuilder/composer.json",
                "core/lib/Drupal/Component/Render/composer.json",
                "core/lib/Drupal/Component/Serialization/composer.json",
                "core/lib/Drupal/Component/Transliteration/composer.json",
                "core/lib/Drupal/Component/Utility/composer.json",
                "core/lib/Drupal/Component/Uuid/composer.json"
            ],
            "recurse": false,
            "replace": false,
            "merge-extra": false
        }

But @neclimdul I think you raise a good point because with this change maybe we need to add "wikimedia/composer-merge-plugin": "^1.4" to core/composer.json.

Mile23’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
1.66 KB

How about core/composer.json has components in both require and replace?

I just did this and then did composer run-script drupal-phpunit-upgrade (which rebuilds the autoloader).

Then vendor/composer/autoload_psr4.php contains this:

    'Drupal\\Core\\' => array($baseDir . '/core/lib/Drupal/Core'),
    'Drupal\\Component\\Uuid\\' => array($baseDir . '/core/lib/Drupal/Component/Uuid'),
    'Drupal\\Component\\Utility\\' => array($baseDir . '/core/lib/Drupal/Component/Utility'),
    'Drupal\\Component\\Transliteration\\' => array($baseDir . '/core/lib/Drupal/Component/Transliteration'),
    'Drupal\\Component\\Serialization\\' => array($baseDir . '/core/lib/Drupal/Component/Serialization'),
[..etc..]

And I can run tests:

$ ./vendor/bin/phpunit -c core/ core/tests/Drupal/Tests/Component/

[..]

OK, but incomplete, skipped, or risky tests!
Tests: 9286, Assertions: 11224, Skipped: 2147.
alexpott’s picture

@Mile23 yeah but you've still got the merge plugin installed.

Mile23’s picture

Well it didn't break anything is what I'm saying. And then when someone tries to use it in drupal-project etc, it will require the thing it replaces, without merging.

Mixologic’s picture

Issue tags: +Composer
Mixologic’s picture

Ideally we alter the subtree splits such that we split out /core *without* the components nestled inside, and the components get split out separately, and core composer.json merely 'requires' them. But Im not sure we can do this yet, without either modifying the subtree tool to exclude the components subdir, or by moving the components out of /core/lib/ and into something above /core, which Is also the part I dont think we can do (yet)

Mile23’s picture

We were having a conversation about whether to move the stuff around a bunch or leave components in place here: #2943856: [meta] Reorganize Components so they are testable in isolation

Agreed that somehow we should quit doing the replace part, other than maybe for the benefit of dev. In which case we might replace the components in drupal/drupal. But that's getting way ahead on the composer initiative, and not the scope of this issue.

alexpott’s picture

@Mile23 I think if we don't add the merge plugin into core/composer.json then drupal-project from https://github.com/drupal-composer will put the components in vendor/drupal/component which whilst is probably desirable in the long term I'm not sure we should do that here.

Mile23’s picture

Status: Needs review » Reviewed & tested by the community
FileSize
407 bytes

OK.

Re-upping #16, originally from @alexpott, so not mine.

I RTBCd in #23, so I'm re-RTBCing here.

webflo’s picture

#34 will break the usage of "drupal/core". It won't be usable without the merge plugin. I think we should get rid of the merge plugin in the long-run. This is a step in the wrong direction imo.

alexpott’s picture

@webflo what about #27? Super tricky...

webflo’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
2.36 KB

This should work without the merge plugin.

Mile23’s picture

Status: Needs review » Needs work

Moving away from the merge plugin is the goal. But we can't even test the validity of the components' composer.json files until we allow them to define their own autoloading and version constraints. The easiest way to make that work without breaking everything else seems to be merging them.

When we have a way to test them, we can then remove the merge plugin.

The patch in #37 basically reverts #2867960: Merge Component composer.json files to account for them during build which was a previous step along this path. It also does not allow for the components to define their own autoloading.

We can test the validity of the version constraints using TravisCI in #2876669: Fix dependency version requirement declarations in components but we need to be able to prove it using DrupalCI, so we can prevent regressions.

Also re: #32: Using replace in drupal/drupal for dev is kind of the plan now: #2958021: Proposal: Composer Support in Core initiative (We had even talked about renaming drupal/drupal to drupal/drupal-dev.) But yah, that's out of scope here.

webflo’s picture

I think we should move the test from core/tests/Drupal/Tests/Component to their components. And test them individually in Drupal CI (pseudocode: for each component => composer install && ./vendor/bin/phpunit). We could still run them in our normal testsuite as well.

It takes on 12 seconds on my machine. It should be possible from infrastructure perspective. Maybe @Mixologic could comment on this?

alexpott’s picture

IF we do #39 we need to put stuff into out composer.json to make sure that component tests are not autoloadable during regular runtime. As an aside imo we should also move completely away from autoloadable tests as well as the merge plugin. Changing the autoloader for testing is not our best idea.

webflo’s picture

Status: Needs work » Needs review
FileSize
61.62 KB

The composer.json in our components does not follow our conding standards. We could fix this is a separate before moving the test classes.

Status: Needs review » Needs work

The last submitted patch, 41: 2943842-41.patch, failed testing. View results

Mile23’s picture

See #10 and #11.

Also we can rescope #2876669-55: Fix dependency version requirement declarations in components to be about changing DrupalCI once we've done this and #2943856: [meta] Reorganize Components so they are testable in isolation

+++ b/core/tests/bootstrap.php
@@ -134,6 +134,13 @@ function drupal_phpunit_populate_class_loader() {
+  // Add tests from drupal components.
+  $components = glob(__DIR__ . '/../lib/Drupal/Component/*', GLOB_ONLYDIR);
+  foreach ($components as $componentPath) {

We should make the components test a separate testsuite rather than changing bootstrap.php.

But that's out of scope here... We should only set up autoloading via composer.json in this issue, for consistency against the existing test setup.

webflo’s picture

Status: Needs work » Needs review
FileSize
60.95 KB

Status: Needs review » Needs work

The last submitted patch, 44: 2943842-43.patch, failed testing. View results

webflo’s picture

Status: Needs work » Needs review
FileSize
60.95 KB

This one could apply, my local repo was outdated. It does not address the review from @Mile23 yet.

webflo’s picture

webflo’s picture

I tried to use the merge plugin in an test to verify we have no conflicts between component constraints and drupal/core.

webflo’s picture

Lets move the new composer.json to a different location to avoid autoloading of tests.

The last submitted patch, 48: 2943842-48.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Mile23’s picture

Status: Needs review » Needs work

Getting a bit out of scope here.

Will #27 work for drupal-project?

When we have either #27 or #34 (really #16) working without changing tests, we can then change the tests around and work on DrupalCI in #2943856: [meta] Reorganize Components so they are testable in isolation which is postponed on the narrow scope of this issue.

webflo’s picture

I guess #27 would work for drupal-project. #34 definitely not.

But #27 makes the composer.json for drupal/core more complex. I tried to optimize it for distribution, hence i remove the merge-plugin from drupal/core which only purpose it is to test the the components in combination with drupal/core.

Mixologic’s picture

Can we leave the merge in there, except move it all the way to the top level drupal/drupal composer.json?

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Mile23’s picture

Rescoping here a tiny bit in order to support #1826054: [Meta] Expose Drupal Components outside of Drupal and #2982674: [meta] Composer Initiative Phase 1: Add composer build support to core and #2912387: Stop using wikimedia/composer-merge-plugin

Let's use path repositories to allow drupal/drupal to install the components locally.

Then we don't merge/replace the components in drupal/core, and require them instead.

This removes this usage of the merge plugin for this purpose, while still allowing us to exercise the component composer.json files.

Here's the composer update command to save you some typing:

composer update drupal/core-annotation drupal/core-assertion drupal/core-bridge drupal/core-class-finder drupal/core-datetime drupal/core-dependency-injection drupal/core-diff drupal/core-discovery drupal/core-event-dispatcher drupal/core-file-cache drupal/core-filesystem drupal/core-gettext drupal/core-graph drupal/core-http-foundation drupal/core-php-storage drupal/core-plugin drupal/core-proxy-builder drupal/core-render drupal/core-serialization drupal/core-transliteration drupal/core-utility drupal/core-uuid drupal/core-version
Mile23’s picture

Status: Needs work » Needs review
Mile23’s picture

The error in #56 was this: Source path "core/lib/Drupal/Component/DateTime" is not found for package drupal/core-datetime

That's because the testbot uses a case-sensitive filesystem, and the directory is actually named Datetime.

Interestingly, if you say composer update on a branch other than 8.8.x, Composer will be unable to resolve the components due to weird version inconsistencies with error reports that look like this: - Installation request for drupal/core-utility 2943842.9999999.9999999.9999999-dev -> satisfiable by drupal/core-utility[2943842.x-dev].

Furthermore, if you were to get them to resolve, the lock file would lock to version 2943842.x-dev, which would not install if you're on branch 8.8.x because self.version resolves to version 8.8.x-dev.

I also discovered that there is a dependency between "post-autoload-dump": "Drupal\\Core\\Composer\\Composer::ensureHtaccess", and one of the components. This means that there are plenty of error conditions where Composer dumps the autoloader before running the plugins, such as the merge plugin that we're still using for drupal/core. That leads to a nice dependency trainwreck. This event script will go away in #2982684: Add a composer scaffolding plugin to core (see: #2990257: Determine how to handle composer scripts in drupal/drupal) We'll need to commit that before we cut the Gordian knot here.

greg.1.anderson’s picture

I think that #2912387: Stop using wikimedia/composer-merge-plugin has advanced to the point where this patch is no longer necessary.

greg.1.anderson’s picture

Or maybe I am wrong about that. I am not sure we can move the Component sources into a src directory.

greg.1.anderson’s picture

We should still be able to isolate and test the components separately, if desired, as long as we are content to do without the src directory. Note that this is the technique that Symfony uses, and as a result, Symfony forgoes the src directory in each component tree.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Mile23’s picture

This is the same strategy as #58: Path repos for components in drupal/drupal, and direct require in drupal/core.

Handy composer command for anyone who wishes to copy/paste:

COMPOSER_ROOT_VERSION=8.9.x-dev composer update drupal/core-annotation drupal/core-assertion drupal/core-bridge drupal/core-class-finder drupal/core-datetime drupal/core-dependency-injection drupal/core-diff drupal/core-discovery drupal/core-event-dispatcher drupal/core-file-cache drupal/core-file-security drupal/core-filesystem drupal/core-gettext drupal/core-graph drupal/core-http-foundation drupal/core-php-storage drupal/core-plugin drupal/core-proxy-builder drupal/core-render drupal/core-serialization drupal/core-transliteration drupal/core-utility drupal/core-uuid drupal/core-version

#3086644: LegacyProject composer templates wrongly reference 8.x + fix test coverage is RTBC, so it's likely that it will make it in first. That means we'll have to change that test here, to include more path repos in our build tests.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Mile23’s picture

Tried to re-roll this but I ran into dependency issues based on #3272110: Drupal 9 and 10's Drupal\Component composer.json files are totally out of date, so I'm marking this as postponed on that one.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Mile23’s picture

Status: Postponed » Needs review
FileSize
131.55 KB

#3272110: Drupal 9 and 10's Drupal\Component composer.json files are totally out of date is in, so here’s this.

This patch changes the drupal/drupal root composer.json to require drupal/core 11.x-dev, but it’s the only way I could get it to work. This might imply that we need to specify the major/minor dev branch for each branch, which could be a drag.

smustgrave’s picture

Status: Needs review » Needs work

Have not tested but seems to have caused some test failures.