Add opt-in Composer dependency scoping (#309)#537
Open
srtfisher wants to merge 6 commits into
Open
Conversation
Scaffolded plugins can opt into prefixing their runtime Composer dependencies into vendor-prefixed/ via php-scoper, isolating them from other plugins or the host project when loaded as a Composer dependency. - .scoper/scoper.inc.php: namespace-agnostic php-scoper config that derives the prefix from composer.json and scopes runtime packages only. - .scoper/scope.php: orchestrator that runs php-scoper then regenerates a classmap autoloader over the scoped files + the plugin's own src, carrying autoload.files (helper functions) forward. No-ops without php-scoper so it is safe in post-install/post-update hooks. - configure.php: opt-in prompt (default off) that wires the tooling, rewrites the plugin loader + the finite set of vendor imports, and enables the scoped-build CI workflow; removes the machinery otherwise. - .github/workflows/test-scoped.yml: PR test that scopes then runs phpunit against the scoped dependencies (enabled by configure.php on opt-in). Verified by scaffolding a plugin, requiring symfony/string, and running phpunit (2 passed) against the scoped autoloader.
When scoping is enabled, configure.php now wires built-release.yml to call action-release with scope: true, so the built branch ships the prefixed vendor-prefixed/ directory.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #309.
What
Scaffolded plugins can opt in (default off) to prefixing their runtime Composer dependencies into
vendor-prefixed/via php-scoper, so they no longer conflict with other plugins or the host project when loaded as a Composer dependency. The dominant collision source is Alley's own shared packages (wp-type-extensions,mantle-framework/support) shipping at different versions across plugins.How
.scoper/scoper.inc.php— namespace-agnostic config. Derives the prefix (<RootNamespace>\Dependencies) fromcomposer.json, scopes runtime packages only (fromcomposer.lock'spackages, so dev tools are never scoped), and excludes WordPress core symbols (sniccowp/php-scoper-wordpress-excludes) + the plugin's own namespace (AC Bump nick-invision/retry from 1 to 2.6.0 #2)..scoper/scope.php— orchestrator. Runs php-scoper, then regenerates aclassmap-authoritativeautoloader over the scoped files + the plugin's ownsrc/, rebuilding each runtime package'sautoload.filesso scoped helper functions still load. No-ops when php-scoper is absent (safe inpost-install/post-updatehooks and under--no-dev).configure.php— opt-in prompt that wires the tooling +scopescript + hooks, repoints the plugin loader tovendor-prefixed/vendor/autoload.php, prefixes the finite set of vendor imports insrc/, and enables the CI workflow. Removes all of it when declined..github/workflows/test-scoped.yml— PR test that scopes then runs phpunit against the scoped dependencies (AC Bump styfle/cancel-workflow-action from 0.5.0 to 0.9.1 #4); enabled byconfigure.phpon opt-in.Why classmap regeneration (not php-scoper's autoloader)
php-scoper scopes files reliably, but its autoloader output is unusable here: the Alley packages use the WordPress autoloader (no PSR-4), so some
registerFromRules()namespace strings are left unprefixed, and its scoped Composer bootstrap fails to loadClassLoader. Regenerating a classmap autoloader parses actual class declarations, so PSR-4 and WordPress-autoloader packages are handled uniformly — which is why Strauss wasn't needed.Verification
composer require symfony/string(auto re-scoped to 1606 classes).register_meta_from_fileresolve; the unscopedAlley\WP\Features\Groupis correctly absent.composer phpunit→ OK (2 tests, 3 assertions) — the Feature test boots the whole plugin through the scoped autoloader.Follow-ups (not in this PR)
alleyinteractive/action-releaseneeds a backward-compatiblescopeinput that runscomposer scopeand enables the require-pruning step currently commented out citing this issue. (Separate PR.)configure.php's'alleyinteractive' => $vendor_slugreplacement rewrites Alley dependency package names for non-Alley vendors, breakingcomposer update. Unrelated to Allow Composer Dependencies to be scoped #309.Design spec and implementation plan included under
docs/superpowers/.🤖 Generated with Claude Code