Problem/Motivation
The package_manager module that will be added to Drupal core for both https://www.drupal.org/project/automatic_updates and https://www.drupal.org/project/project_browser has a dependency on:
php-tuf/composer-stager":"^2"
— see the composer.json
When Automatic Updates or Project Browser needs to run Composer commands that will modify any of the site's code (e.g., composer require, composer update, or composer remove), the Composer Stager library is what copies the site's entire codebase to a separate directory, runs the composer commands in that separate directory, and then syncs the changes back to the site's real codebase. In other words, this library is what ends up modifying the site's actual code files, so it's essential that we have confidence in its reliability and security, both when we initially add it to Drupal core, and ongoing after that.
So far, 99% of Composer Stager has been written by @TravisCarden, a Drupal contributor working for Acquia as part of Acquia's investment in the Automatic Updates initiative. The Composer Stager library does not make Drupal-specific assumptions and was written with the hope that other Composer-managed PHP CMSes and applications could also some day benefit from it and contribute to it.
Proposed resolution
Place the Composer Stager library into core governance. This would mean, for example, all Drupal core committers having commit access to it, following Drupal core review processes for committing to it, and having a security policy in the repo that states that security issues should be reported according to Drupal's security reporting process.
Existing maintainers would maintain commit access to the repository, but should co-ordinate any new releases or major changes with core committers.
Dependency evaluation
Per https://www.drupal.org/about/core/policies/core-dependency-policies/depe... :
- Repository
- https://github.com/php-tuf/composer-stager
- Code quality
- The project has extensive unit and functional test coverage, strict static analysis, and automated coding standards.
- Maintainership of the package
- Currently by @TravisCarden, but the Proposed Resolution is to place this under Drupal core maintenance.
- Security policies of the package
- The current github repo does not have a security policy, but the Proposed Resolution is to place this under Drupal core maintenance and therefore under Drupal core security policies. See the Add SECURITY.md pull request.
- Expected release and support cycles
- To be determined by Drupal core release managers as part of placing this under Drupal core governance.
- Other dependencies it'd add, if any
-
Runtime dependencies
symfony/process: Already a direct Drupal core runtime dependency.symfony/translation-contracts: Already an indirect Drupal core runtime dependency viasymfony/validator.symfony/filesystem: Currently a Drupal core dev dependency, but @catch approved it being promoted to a runtime dependency in https://github.com/php-tuf/composer-stager/issues/60#issuecomment-154401....
Dev dependencies
Composer Stager has 20ish dev dependencies. See https://github.com/php-tuf/composer-stager/issues/78 for links to the child issues to evaluate each one.
Remaining tasks
- Since the repo will be under core governance, perform a dependency evaluation of all dev dependecies, as we would if we were adding that as a core dev dependency (https://github.com/php-tuf/composer-stager/issues/78).
- Review the code that's in Composer Stager for core quality standards.
- Add needed governance documents (security policy, links to Drupal core governance documents, etc.) to the repo. (https://github.com/php-tuf/composer-stager/issues/79)
- Create governance to be completed in #3474816: Governance for projects on Github
- Decide where to document the dependency
Code overview for reviewers
Composer Stager's README and Wiki, which includes a glossary, are a good place to start. In addition to what's written there, the following is a quick orientation to the project's codebase. Read at least either that README or that glossary first, in order to understand the purpose of Composer Stager's four core operations (Begin, Stage, Commit, and Clean), before reading the following.
API vs Internal
The repository has two top-level directories within /src: API and Internal. All files within the API directory are annotated with @api. All files within the Internal directory are annotated with @internal. Almost all interfaces are part of the API and almost all concrete classes are Internal. There are a few exceptions, and it's hopefully clear when reviewing the code why a few interfaces are internal and why a few concrete classes are part of the API.
Preconditions
For each of the 4 core operations (begin, stage, commit, clean), there are preconditions that must all pass. For example, for the begin operation, there's a precondition that the staging directory must not already exist. See the constructors of BeginnerPreconditions, StagerPreconditions, CommitterPreconditions, and CleanerPreconditions, to see the required preconditions of the corresponding operation.
Several preconditions include checking for the presence of hard links or unsupported symlinks. The reason for checking for these is that the premise of Composer Stager is that once the active codebase is copied to staging, then Composer operations in staging won't affect the live site. However, if the codebase includes, for example, symlinks to absolute file paths, then copying that to staging will result in the staging copy pointing to the same place that the active codebase points to, which would open the risk that something that writes to that could end up affecting the live site. However, relative symlinks that don't traverse outside of the project root are allowed (except on Windows, which adds other challenges to working with symlinks that we decided to punt to later), because having those is common for codebases that include Drush, local path repositories, or other use cases.
Several preconditions, such as the ones that check for hard links and symlinks per above, require iterating every directory and file in the codebase being operated on. This iteration is performed by AbstractFileIteratingPrecondition, which uses FileFinder, which in turn uses PHP's RecursiveDirectoryIterator.
Because the codebase could be quite large (e.g., a site with a lot of contrib modules) and iterating each file in PHP could be slow, Composer Stager performs automated benchmarking of these operations as of version 2.0.0-beta1. See https://github.com/php-tuf/composer-stager/pull/230 for details. Current results indicate that for a codebase that includes Drupal core plus the ~130 most installed contrib modules that each of the expensive operations (begin and commit) takes on the order of 15-30 seconds on GitHub Actions containers. That time includes the combined time of both running the preconditions and then performing the file sync operation itself.
File syncers: Rsync and PHP
The Begin operation copies the codebase (the entire Drupal application) from its live location (the "active" directory) to a temporary location (the "staging" directory). The Commit operation (which is called after all of the desired Composer commands have finished operating on the staging directory) copies back. On systems that have rsync available, RsyncFileSyncer is used. Otherwise, PhpFileSyncer is used. We expect RsyncFileSyncer to be significantly faster than PhpFileSyncer, especially for the Commit operation which only needs to sync back the files that are different (i.e., the ones that changed as a result of the Composer commands that ran in the staging directory), which rsync is very efficient at doing. The speed of the Commit operation matters, since Package Manager puts the Drupal site into maintenance mode during that time so as not to serve requests during the time that files are being copied from staging to active (i.e., when the live codebase is in a partially updated state).
Exclusions
One of the parameters to Beginner::begin() and Committer::commit() is $excusions. Composer Stager is un-opinionated about what codebase it's being used on, so it defaults this to NULL, but Package Manager passes several directories to it, including sites/default/files. This is the set of paths to exclude from copying. This is so that the Drupal site can still serve requests (and content editors can still be uploading files) while Composer commands are running in the staging directory. Without excluding these, the Commit operation would delete/undo changes that were made on the live site since the time that the Begin operation ran.
String translations
All potentially user-facing strings within Composer Stager's code files are translated via TranslatableAwareTrait::t(). This should hopefully make it easy for Drupal's POTX to find them. The implementation of this t() method uses a Composer Stager translation API that's modeled on Symfony's translation contracts component (not on Drupal's translation API, since Composer Stager is intended to be Drupal-agnostic). Drupal's Package Manager module overrides Composer Stager's translation factory service to return a Drupal-compatible TranslatableMarkup object. See #3368808: Override Composer Stager's TranslatableFactory to return Drupal's TranslatableMarkup for details.
Release notes snippet
php-tuf/composer-stager is now a dependency, which enables the experimental Automatic Updates and Project Browser functionality.
| Comment | File | Size | Author |
|---|---|---|---|
| #50 | 3331078-50.patch | 11.77 KB | effulgentsia |
| #42 | 3331078-42.patch | 11.81 KB | effulgentsia |
| #41 | 3331078-41.patch | 11.09 KB | effulgentsia |
| #26 | 3331078-26.patch | 12.08 KB | wim leers |
| #26 | interdiff.txt | 1.32 KB | wim leers |
Issue fork drupal-3331078
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
- 3331078-add-php-tufcomposer-stager-to
changes, plain diff MR !9408
Comments
Comment #2
wim leersHah, oops, the issue title is clearly copy/pasted from #3321905: Add colinodell/psr-test-logger to core's dev dependencies 🙈
Other example issues that add dependencies are: #3178534: Start running PHPStan on Drupal core (level 0), #2843147-117: Add JSON:API to core as a stable module and #2550717: [JS] Replace jQuery.cookie with JS-cookie and provide a BC layer.
Since @TravisCarden is the lead developer of this library, marking this so he can answer the remaining questions of the dependency evaluation 🤓
Comment #3
wim leersRelated: we should document here and in #3318306: Define the Package Manager API (package_manager.api.php is outdated) where the boundaries lie between
php-tuf/composer-stager's responsibilities and those ofdrupal/package_manager.Comment #4
traviscarden commentedComment #5
wim leers@TravisCarden: I think that update is incomplete? Or are you implying that despite you being the lead developer of this library, that there is no maintenance planned, and hence also no time from you to help with security issues when they arise?
At minimum, I think you could say it complies with
semver?Also: #3 is not yet covered in the issue summary.
Comment #6
xjmOf note: We intend these Composer packages related to the AU toolchain to eventually be maintained by the core maintainers and treated essentially as a part of core. So I would encourage other RMs and FMs to do very thorough review of the code.
Comment #7
traviscarden commentedJust to be explicit, @Wim Leers, since the current plan is for Drupal core maintainers to completely take over ownership and maintenance, I think all the other questions in the summary are pending the details of that plan.
Comment #8
effulgentsia commentedI updated the issue summary based on #6. It's possible that I misunderstood the implications of that comment, so if anything in the issue summary looks incorrect, please correct it.
Comment #9
traviscarden commentedUpdating the issue summary to reflect the decision made with @effulgentsia to eliminate the dependency on
symfony/filesystem.Comment #10
wim leersI never looked at this again because it was still marked . But it looks like ever since #9, it's been ready for review 😅
Slightly tweaked the issue summary markup for easier reading 👍
Comment #11
effulgentsia commentedOne necessary next step here is to open issues for each of Composer Stager's dev dependencies that isn't already a core dev dependency, that explains the benefit of that dev dependency, so that we can evaluate whether the benefit is worth whatever the burden of that dependency is.
https://github.com/php-tuf/composer-stager/issues/56 is an example where we've started the discussion for
infection/infection, and I think the conclusion there so far is to remove that dependency unless @TravisCarden wants to argue for keeping it.Reviewing the code itself can happen in parallel to that, so I agree with "Needs review" as the correct issue status here.
Comment #12
effulgentsia commentedRemoving these from the remaining tasks, because I discussed this with other committers, and we decided to keep it in the PHP-TUF namespace and on GitHub, to make it easier for other projects (e.g., Joomla, Typo3) to co-maintain it with us if they want to.
I replaced that with:
Comment #13
effulgentsia commentedAdded a remaining task of performing evaluations for Composer Stager's dev dependencies. https://github.com/php-tuf/composer-stager/issues/78 is the issue for that (currently that issue only lists one dev dependency but the others will be added to it soon).
Comment #14
effulgentsia commentedAdded link to https://github.com/php-tuf/composer-stager/issues/60.
Comment #15
traviscarden commentedAdding a link to the summary to the Composer Stager issue to define a security policy (https://github.com/php-tuf/composer-stager/issues/79).
Comment #16
effulgentsia commentedI added a "Code overview for reviewers" section to the issue summary to help orient reviewers.
Comment #17
wim leers👏 That looks excellent, @effulgentsia!
Comment #18
pwolanin commentedDiscussing this at DrupalCamp NJ. I think it would be worth shipping a composer.phar with Drupal core so that there is a known and valid version of the composer executable always available.
Advantages:
You can always be using a version of composer against which all the automated/manual tests have run and passed.
There is no dependency on the hosting provider to have installed a usable version of composer
There might be other ways to handle a missing or invalid composer, but this is at least simple. since it's just a phar, it's not going to be the composer/composer package which is causing issues mentioned by Dave in #3243899: [policy] Move composer/composer from a dev dependency to a production dependency
Another option... maybe trickier... would be to download the phar if needed to a temp location and execute it. The phar files do have an RSA signature available.
Comment #19
pwolanin commentedAlso, there should be a way to run the autoupdates on the cli so that you can run as a system user that can write the files. Possibly we could update core/scripts/drupal to include some commands that actually bootstrap to do those things in a light-weight way?
Comment #20
wim leershttps://github.com/php-tuf/composer-stager/releases/tag/v2.0.0-alpha1 was tagged.
See https://github.com/php-tuf/composer-stager/milestone/1 for what remains to reach
2.0.0.This patch adds
php-tuf/composer-stager2.0.0-alpha1to Drupal core and was generated usingComment #21
dwwThanks for such a comprehensive summary! I hope to have time to review this “soon”. 🤞 meanwhile, I hope adding “and governance” to this title is a friendly amendment, because that’s the full scope here, no?
Comment #22
wim leersComposerProjectTemplatesTestfails because2.0.0-alpha1does not meet the minimum stability ofstable.Not sure how we want to proceed here because https://www.drupal.org/about/core/policies/core-change-policies/experime... does not document either:
… but given that this is an alpha-experimental module, a dependency on an alpha release of a package that as @xjm said in #6 we are actually maintaining … seems reasonable?
Comment #25
wim leers#20 had 3 failures, #22 has 2. But the 2 failures already fail locally on a fresh Drupal core clone … 🤔😬
Fortunately the error message is clearer on DrupalCI than on my local — they fail like this:
That's pretty clear. AFAICT that means this is hard-blocked on a
2.0.0tag ofphp-tuf/composer-stager?Comment #26
wim leersAttempting a work-around: use a stability flag to bypass core's requirement: https://getcomposer.org/doc/04-schema.md#package-links.
Comment #27
wim leersThis blocks #3346707: Add Alpha level Experimental Package Manager module, which in turn blocks Automatic Updates (#3253158: Add Alpha level Experimental Update Manager module) and Project Browser (no core issue yet — roadmap: #3316151: Roadmap to experimental Project Browser in Drupal Core).
Comment #28
wim leersLooks like #26 will still fail.
Still, it doesn't even really matter: @tedbow pointed out that he actually thinks the very goal is to have an
alpharelease ofphp-tuf/composer-stager:What do core framework managers & release managers think? 😊
Comment #30
effulgentsia commentedI think that the patch for this issue can/should change
ComposerProjectTemplatesTest::MINIMUM_STABILITYfrom "stable" to "alpha". I think it's okay to do that, because after we branch 10.2.x, we can remove this dependency from 10.1.x and then raiseComposerProjectTemplatesTest::MINIMUM_STABILITYback to what we want to prior to tagging any 10.1 pre-releases.Comment #31
effulgentsia commented@pwolanin, re #18 and #19, that's really good feedback, but I think #18 is a topic for #3346707: Add Alpha level Experimental Package Manager module and #19 is a topic for #3253158: Add Alpha level Experimental Update Manager module. Do you agree, or do you see those as something in scope for Composer Stager?
The sequence of issues is:
Comment #32
wim leers#30: AFAICT that won't work either, since
ComposerProjectTemplatesTest::MINIMUM_STABILITYis used for asserting expectations, not for setting the actual minimum stability. AFAICT we need something like:… but I'm not sure if that'll be acceptable 😅
Comment #33
traviscarden commentedI'll try to post some updates here as I make progress toward a stable
v2.0.0release of Composer Stager. I finished two issues on the milestone checklist today. (I also explicitly marked (annotated) the API surface.) Of the two remaining issues, one should be fairly simple. Eliminating the dependency on Symfony Filesystem could potentially take some doing (but I can't say until I get started). I do also plan to add an issue to the milestone for some refactoring that I want to do while I can still make BC-breaking changes. I don't want that opportunity to get away, but I'm trying not to go crazy.Comment #34
wim leersFor #33 — we indeed need to document where we're at and what remains on this issue to make it actually realistically reviewable by framework managers & release managers.
Comment #35
romulasry commentedTell me when you push this dependency onto stable so I can update. Thanks.
Comment #36
traviscarden commentedUpdate from my end: I'm continuing to work on the
Composer Stager v2.0.0 milestone, most notably Add support for string translation for names, descriptions, and messages. Things are moving along nicely, but there's a non-trivial amount of work left.Comment #37
traviscarden commentedUpdate: there's ongoing requirements-and-design discussion on Add support for string translation for names, descriptions, and messages. The scope has increased somewhat as a result, and there's still quite a bit of work left. But it's still moving along at a good pace without any surprises.
Comment #39
traviscarden commentedUpdate: Add support for string translation for names, descriptions, and messages is finished. There are some follow-ups and of course the other issues assigned to the v2.0.0 milestone.
Comment #40
effulgentsia commentedComposer Stager 2.0.0-beta1 has been released. I updated the issue summary to be up to date with that.
I believe Composer Stager now implements everything that is needed for an Automatic Updates in Drupal core MVP and is therefore fully ready for reviews.
Comment #41
effulgentsia commentedUpdated patch to pull in the 2.0.0-beta1 version.
Comment #42
effulgentsia commentedComment #43
effulgentsia commentedFixed broken links in the issue summary that were due to refactoring of class names from 1.x to 2.x.
Comment #44
traviscarden commentedComment #45
wim leersSo weird that
composerjust moved this exact same dependency around incomposer.lock! 🙃🤷♂️You can see that even the hash is identical.
It appears that different
composerversions just have different sorting logic?EDIT: ah, now I see — it is being moved from the pinned dev dependencies to an indirect non-dev dependency. That explains it 👍
Is this really acceptable? 🤔
We usually only do this when updating Symfony to the release we know we'll ship the next Drupal core minor with. For example, #3338328: Update to Symfony 6.3 changed this to
'beta'too, then #3361949: Update to Symfony 6.3 RC1 changed it to'RC'and #3363222: Update to Symfony 6.3 restored it to'stable'.I guess we're saying … that it'll be okay to set this temporarily, because we'll pin it to a stable release of
php-tuf/composer-stagerprior to tagging Drupal 10.2?🤔 Arguably, this is wrong. Or rather, the assertions associated with this are wrong:
This is wrong because it means that this test is testing something that violates Composer's stability flags:
Whenever a stability flag is encountered, it should be special-cased.
OTOH this comment in the test:
explains WHY we are doing it this specific way.
So … 👍
Comment #46
catchWe have test coverage that when we tag an rc (I think) will fail if the minimum stability doesn't match - so it becomes rc-blocking to sort out. As you point out we usually only do it with Symfony because their release timelines are pretty reliable, but I think it's OK to apply the same pattern here.
Comment #48
wim leersKnown, unrelated random fail:
Comment #50
effulgentsia commented#49 looks like a random failure, but this rerolls for composer.lock changes since #42, and also updates the composer-stager requirement to beta3.
Back to RTBC, optimistically assuming it'll pass tests. Note that the RTBC is for the patch itself, but putting composer-stager under core governance still requires framework and release manager review of composer-stager itself, per this issue's tags.
Yeah, in this case, part of putting composer-stager into core governance, is then its release timeline is under our control. Also, there are currently no known issues blocking a stable 2.0.0 release of composer-stager. Only thing keeping it at beta right now is that it hasn't been reviewed by any Drupal core committers other than me.
Comment #52
effulgentsia commentedI think #51 is a random failure. Queued a re-test and optimistically re-RTBC'ing.
Comment #54
xjmTwo different randoms.
Comment #55
catchMy main concern here is that the committer team routinely struggles to keep the RTBC queue under 150 issues at a time, and this adds a separate queue on a separate system to manage, with a code base that is entirely new to most committers.
So what I would propose is we add core committers to the github repo, but in addition to the existing maintainers, not instead. We can figure out exactly what responsibilities are as time goes on, but an immediate switch from one set of maintainers to another doesn't seem like a good idea.
Comment #56
xjmRight, and core maintainers will still control which versions are pinned in
core-recommendedat least. I'd suggest this:Comment #57
xjmThis is hopefully only a temporary change, like we make between alpha and RC for core for Symfony? If so we need a followup to switch it back before 10.2.0-rc1.
Comment #58
xjmAlso possibly we should branch 10.2.x (which we are planning to do ASAP) before we actually commit this, since needing to revert lockfile changes before RC would be messy. (And we don't want to ship it unless we're also shipping AU and/or PB, which remains to be seen.)
Comment #59
xjm@catch and I both would really like to see some of the excess dev dependencies eliminated. If possible, let's please focus on dev deps that core already uses. E.g., seems what grumphp is doing could mostly be accomplished with phpcs and phpstan etc.? I saw https://github.com/php-tuf/composer-stager/issues/78 but in a way this is almost asking release managers to do too much work. Dev dependencies core already has for dev or prod are fine and don't even need their own evaluations, but I'd really like to see fewer additional dependencies proposed, and a strong case made as to why they are essential to the maintenance of the package.
Also, let's get a followup for #57, and an issue in the composer-stager queue to add a
GOVERNANCE.mdwhere we can start documenting the above stuff?Comment #60
traviscarden commented@xjm: Evaluate dev dependencies · Issue #78 · php-tuf/composer-stager has been updated with issues for each dev dependencies, including justifications for each. I've knocked off a half dozen I felt OK about eliminating without debate.
And I have created Create a governance policy · Issue #300 · php-tuf/composer-stager
Comment #61
catchI've added:
to the issue summary since I think that represents the current plan.
Comment #62
catchComment #63
quietone commentedThis is reasonable place to start. And there will certainly be an evolution of the responsibilities of the roles and the points in #56 indicate a direction on that.
Comment #64
effulgentsia commentedTagging for issue summary update now that https://github.com/php-tuf/composer-stager/releases/tag/v2.0.0-beta4 was released, which removed the PHP filesyncer per #3416542: [policy] Require rsync for automatic updates in Drupal core and punt other syncers to contrib.
Comment #65
effulgentsia commentedhttps://github.com/php-tuf/composer-stager/issues/350 just got completed, making Composer Stager compatible with both Symfony 6 and 7, so that it's compatible with Drupal 10 and 11. So next steps for this issue are:
Comment #67
jofitzAssigning to myself as I take a first pass at the merge request
Comment #69
catchComment #70
alexpottThis went in as part of #3346707: Add Alpha level Experimental Package Manager module
Comment #71
catchWe still need to do the governance steps here. I'm not sure what's left but there's no other issue to track that in.
Comment #72
catchComment #73
andypostThis dependency becomes a blocker for stable release, see #3490163: Update Composer dependencies for 11.1.0
Comment #74
larowlanComment #76
quietone commentedThe governance discussed is moved to #3474816: Governance for projects on Github.
A decision needs to made if the dependency evaluation stays here and the issue is tagged according to Dependency information links or if it is copied to Current PHP dependencies. Setting to NW for this.
alexpott closed this issue, so I am removing the 'Needs framework manager review' tag. I think all the followups needed are done, removing tag.
Comment #77
quietone commentedUpdating title per the last comment
Comment #78
larowlanComment #80
star-szrAttempting to pull out some next steps:
I'm not sure if all Drupal core committers have commit access, can we verify that?
For "following Drupal core review processes for committing to it", maybe that falls under https://github.com/php-tuf/composer-stager/issues/300 (Governance)? There is a basic docs/GOVERNANCE.md but that may not be very definitive/helpful. Calling this out in the README or somewhere more prominent may be worth considering.
The GitHub issue for the security policy is open, and seems to have some relatively clear next steps. I will note that there is currently a docs/SECURITY.md in the repository (the "issue summary" of that issue is slightly out of date).
Comment #81
quietone commentedThe policy statement is in the Drupal Governance and the projects on GitHub should simply link to it; https://git.drupalcode.org/project/governance/-/blob/main/external-proje....
But that should be a link to the docs, not the repo, but the menu didn't get updated when that change was made. I'll make an issue to fix that sometime today.